@dataemergencia/emergency 0.5.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/dist/iife/emergency.iife.global.js +2 -2
- package/dist/index.cjs +584 -95
- package/dist/index.js +584 -95
- package/dist/styles.css +272 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1547,6 +1547,12 @@ var panel_module_default = {
|
|
|
1547
1547
|
"de-emergency-slide-in": "de-emergency-de-emergency-slide-in-nA5Hwa",
|
|
1548
1548
|
"de-emergency-slide-up": "de-emergency-de-emergency-slide-up-nA5Hwa",
|
|
1549
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",
|
|
1550
1556
|
"emergency-availability": "de-emergency-emergency-availability-nA5Hwa",
|
|
1551
1557
|
"emergency-availability__card": "de-emergency-emergency-availability__card-nA5Hwa",
|
|
1552
1558
|
"emergency-availability__card-body": "de-emergency-emergency-availability__card-body-nA5Hwa",
|
|
@@ -1570,6 +1576,19 @@ var panel_module_default = {
|
|
|
1570
1576
|
"emergency-confirmation__icon--information": "de-emergency-emergency-confirmation__icon--information-nA5Hwa",
|
|
1571
1577
|
"emergency-confirmation__text": "de-emergency-emergency-confirmation__text-nA5Hwa",
|
|
1572
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",
|
|
1573
1592
|
"emergency-error-message": "de-emergency-emergency-error-message-nA5Hwa",
|
|
1574
1593
|
"emergency-error-message__container": "de-emergency-emergency-error-message__container-nA5Hwa",
|
|
1575
1594
|
"emergency-error-message__content": "de-emergency-emergency-error-message__content-nA5Hwa",
|
|
@@ -1580,11 +1599,33 @@ var panel_module_default = {
|
|
|
1580
1599
|
"emergency-error-message__title": "de-emergency-emergency-error-message__title-nA5Hwa",
|
|
1581
1600
|
"emergency-feedback": "de-emergency-emergency-feedback-nA5Hwa",
|
|
1582
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",
|
|
1583
1620
|
"emergency-panel": "de-emergency-emergency-panel-nA5Hwa",
|
|
1584
1621
|
"emergency-panel__availability-region": "de-emergency-emergency-panel__availability-region-nA5Hwa",
|
|
1585
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",
|
|
1586
1626
|
"emergency-panel__body--pre-emergency": "de-emergency-emergency-panel__body--pre-emergency-nA5Hwa",
|
|
1587
1627
|
"emergency-panel__body--pricing": "de-emergency-emergency-panel__body--pricing-nA5Hwa",
|
|
1628
|
+
"emergency-panel__body--primary": "de-emergency-emergency-panel__body--primary-nA5Hwa",
|
|
1588
1629
|
"emergency-panel__body-split": "de-emergency-emergency-panel__body-split-nA5Hwa",
|
|
1589
1630
|
"emergency-panel__body-split--with-availability": "de-emergency-emergency-panel__body-split--with-availability-nA5Hwa",
|
|
1590
1631
|
"emergency-panel__body-title": "de-emergency-emergency-panel__body-title-nA5Hwa",
|
|
@@ -1593,13 +1634,14 @@ var panel_module_default = {
|
|
|
1593
1634
|
"emergency-panel__button--emergency": "de-emergency-emergency-panel__button--emergency-nA5Hwa",
|
|
1594
1635
|
"emergency-panel__button--simulation": "de-emergency-emergency-panel__button--simulation-nA5Hwa",
|
|
1595
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",
|
|
1596
1638
|
"emergency-panel__close-icon": "de-emergency-emergency-panel__close-icon-nA5Hwa",
|
|
1597
|
-
"emergency-panel__divider": "de-emergency-emergency-panel__divider-nA5Hwa",
|
|
1598
1639
|
"emergency-panel__footer": "de-emergency-emergency-panel__footer-nA5Hwa",
|
|
1599
1640
|
"emergency-panel__footer--single": "de-emergency-emergency-panel__footer--single-nA5Hwa",
|
|
1641
|
+
"emergency-panel__footer--square": "de-emergency-emergency-panel__footer--square-nA5Hwa",
|
|
1600
1642
|
"emergency-panel__header": "de-emergency-emergency-panel__header-nA5Hwa",
|
|
1601
|
-
"emergency-panel__header--close-only": "de-emergency-emergency-panel__header--close-only-nA5Hwa",
|
|
1602
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",
|
|
1603
1645
|
"emergency-panel__sr-only": "de-emergency-emergency-panel__sr-only-nA5Hwa",
|
|
1604
1646
|
"emergency-panel__title": "de-emergency-emergency-panel__title-nA5Hwa",
|
|
1605
1647
|
"emergency-panel--hidden": "de-emergency-emergency-panel--hidden-nA5Hwa",
|
|
@@ -1818,18 +1860,27 @@ function useFocusTrap(ref, active) {
|
|
|
1818
1860
|
}
|
|
1819
1861
|
|
|
1820
1862
|
// src/react/screens/context.tsx
|
|
1863
|
+
const EMPTY_PARAMS = {};
|
|
1821
1864
|
const EmergencyScreenContext = createContext(null);
|
|
1865
|
+
function paramsEqual(first, second) {
|
|
1866
|
+
return first.messageId === second.messageId;
|
|
1867
|
+
}
|
|
1822
1868
|
function EmergencyScreenProvider({ children, initialScreen = "primary" }) {
|
|
1823
1869
|
const [state, setState] = useState({
|
|
1824
1870
|
screen: initialScreen,
|
|
1871
|
+
params: EMPTY_PARAMS,
|
|
1825
1872
|
history: []
|
|
1826
1873
|
});
|
|
1827
|
-
const navigate = useCallback((next) => {
|
|
1874
|
+
const navigate = useCallback((next, params = EMPTY_PARAMS) => {
|
|
1828
1875
|
setState((current) => {
|
|
1829
|
-
if (current.screen === next) return current;
|
|
1876
|
+
if (current.screen === next && paramsEqual(current.params, params)) return current;
|
|
1830
1877
|
return {
|
|
1831
1878
|
screen: next,
|
|
1832
|
-
|
|
1879
|
+
params,
|
|
1880
|
+
history: [...current.history, {
|
|
1881
|
+
screen: current.screen,
|
|
1882
|
+
params: current.params
|
|
1883
|
+
}]
|
|
1833
1884
|
};
|
|
1834
1885
|
});
|
|
1835
1886
|
}, []);
|
|
@@ -1838,31 +1889,47 @@ function EmergencyScreenProvider({ children, initialScreen = "primary" }) {
|
|
|
1838
1889
|
const previous = current.history.at(-1);
|
|
1839
1890
|
if (!previous) return current;
|
|
1840
1891
|
return {
|
|
1841
|
-
screen: previous,
|
|
1892
|
+
screen: previous.screen,
|
|
1893
|
+
params: previous.params,
|
|
1842
1894
|
history: current.history.slice(0, -1)
|
|
1843
1895
|
};
|
|
1844
1896
|
});
|
|
1845
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
|
+
}, []);
|
|
1846
1908
|
const reset = useCallback(() => {
|
|
1847
1909
|
setState((current) => {
|
|
1848
|
-
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;
|
|
1849
1911
|
return {
|
|
1850
1912
|
screen: "primary",
|
|
1913
|
+
params: EMPTY_PARAMS,
|
|
1851
1914
|
history: []
|
|
1852
1915
|
};
|
|
1853
1916
|
});
|
|
1854
1917
|
}, []);
|
|
1855
1918
|
const value = useMemo(() => ({
|
|
1856
1919
|
screen: state.screen,
|
|
1920
|
+
params: state.params,
|
|
1857
1921
|
history: state.history,
|
|
1858
1922
|
navigate,
|
|
1923
|
+
replace,
|
|
1859
1924
|
back,
|
|
1860
1925
|
reset
|
|
1861
1926
|
}), [
|
|
1862
1927
|
back,
|
|
1863
1928
|
navigate,
|
|
1929
|
+
replace,
|
|
1864
1930
|
reset,
|
|
1865
1931
|
state.history,
|
|
1932
|
+
state.params,
|
|
1866
1933
|
state.screen
|
|
1867
1934
|
]);
|
|
1868
1935
|
return /* @__PURE__ */ jsx(EmergencyScreenContext.Provider, {
|
|
@@ -1877,12 +1944,11 @@ function useScreenNavigation() {
|
|
|
1877
1944
|
}
|
|
1878
1945
|
|
|
1879
1946
|
// src/react/components/EmergencyHeader/index.tsx
|
|
1880
|
-
function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack
|
|
1881
|
-
const closeOnly = variant === "close-only";
|
|
1947
|
+
function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack }) {
|
|
1882
1948
|
return /* @__PURE__ */ jsxs("header", {
|
|
1883
|
-
className: cls("emergency-panel__header"
|
|
1949
|
+
className: cls("emergency-panel__header"),
|
|
1884
1950
|
children: [
|
|
1885
|
-
onBack
|
|
1951
|
+
onBack ? /* @__PURE__ */ jsx("button", {
|
|
1886
1952
|
type: "button",
|
|
1887
1953
|
className: cls("emergency-panel__close-button"),
|
|
1888
1954
|
"aria-label": copy.back,
|
|
@@ -1893,7 +1959,7 @@ function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack, va
|
|
|
1893
1959
|
})
|
|
1894
1960
|
}) : null,
|
|
1895
1961
|
/* @__PURE__ */ jsx("h2", {
|
|
1896
|
-
className: cls("emergency-panel__title"
|
|
1962
|
+
className: cls("emergency-panel__title"),
|
|
1897
1963
|
id: titleId,
|
|
1898
1964
|
tabIndex: -1,
|
|
1899
1965
|
children: title
|
|
@@ -1912,6 +1978,245 @@ function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack, va
|
|
|
1912
1978
|
});
|
|
1913
1979
|
}
|
|
1914
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
|
+
|
|
1915
2220
|
// src/react/screens/layout.tsx
|
|
1916
2221
|
/**
|
|
1917
2222
|
* Shared shell for every screen. The wrapper is `display: contents` so the
|
|
@@ -1933,46 +2238,254 @@ function EmergencyScreenLayout({ screen, titleId, header, footer, children, body
|
|
|
1933
2238
|
});
|
|
1934
2239
|
}
|
|
1935
2240
|
|
|
1936
|
-
// src/react/screens/
|
|
1937
|
-
|
|
1938
|
-
|
|
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);
|
|
1939
2246
|
return /* @__PURE__ */ jsx(EmergencyScreenLayout, {
|
|
1940
|
-
screen,
|
|
2247
|
+
screen: "details",
|
|
1941
2248
|
titleId,
|
|
2249
|
+
bodyClassName: "emergency-panel__body--details",
|
|
1942
2250
|
header: /* @__PURE__ */ jsx(EmergencyHeader, {
|
|
1943
2251
|
titleId,
|
|
1944
|
-
title,
|
|
1945
|
-
onClose,
|
|
1946
|
-
onBack
|
|
2252
|
+
title: detailsCopy.title,
|
|
2253
|
+
onClose: () => onClose("close"),
|
|
2254
|
+
onBack: back
|
|
1947
2255
|
}),
|
|
1948
2256
|
footer: null,
|
|
1949
|
-
children: /* @__PURE__ */
|
|
1950
|
-
className: cls("emergency-
|
|
1951
|
-
children: /* @__PURE__ */ jsx("
|
|
1952
|
-
className: cls("emergency-
|
|
1953
|
-
|
|
1954
|
-
|
|
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
|
+
})]
|
|
1955
2317
|
})
|
|
1956
2318
|
});
|
|
1957
2319
|
}
|
|
1958
2320
|
|
|
1959
|
-
// src/react/screens/
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
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
|
+
}
|
|
1964
2374
|
|
|
1965
|
-
// src/react/screens/
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
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, {
|
|
1970
2390
|
titleId,
|
|
1971
|
-
title:
|
|
1972
|
-
description: detailsCopy.description,
|
|
2391
|
+
title: messageDetailCopy.title,
|
|
1973
2392
|
onClose: () => onClose("close"),
|
|
1974
2393
|
onBack: back
|
|
1975
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,
|
|
2421
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
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
|
+
})]
|
|
2486
|
+
})
|
|
2487
|
+
})
|
|
2488
|
+
});
|
|
1976
2489
|
}
|
|
1977
2490
|
|
|
1978
2491
|
// src/core/phone.ts
|
|
@@ -1997,9 +2510,9 @@ function toVenezuelanE164(input) {
|
|
|
1997
2510
|
|
|
1998
2511
|
// src/react/components/EmergencyFooter/index.tsx
|
|
1999
2512
|
function EmergencyFooter(props) {
|
|
2000
|
-
const { active, busy, aborting, feedbackVisible, showSimulation = true, emergencyDisabled = false, onActivate, onRequestAbort, onRequestSimulation } = props;
|
|
2513
|
+
const { active, busy, aborting, feedbackVisible, showSimulation = true, emergencyDisabled = false, square = false, onActivate, onRequestAbort, onRequestSimulation } = props;
|
|
2001
2514
|
if (active) return /* @__PURE__ */ jsx("footer", {
|
|
2002
|
-
className: cls("emergency-panel__footer"),
|
|
2515
|
+
className: cls("emergency-panel__footer", square && "emergency-panel__footer--square"),
|
|
2003
2516
|
children: /* @__PURE__ */ jsxs("button", {
|
|
2004
2517
|
type: "button",
|
|
2005
2518
|
className: cls("emergency-status__abort-btn"),
|
|
@@ -2010,7 +2523,7 @@ function EmergencyFooter(props) {
|
|
|
2010
2523
|
})
|
|
2011
2524
|
});
|
|
2012
2525
|
return /* @__PURE__ */ jsxs("footer", {
|
|
2013
|
-
className: cls("emergency-panel__footer", !showSimulation && "emergency-panel__footer--single"),
|
|
2526
|
+
className: cls("emergency-panel__footer", !showSimulation && "emergency-panel__footer--single", square && "emergency-panel__footer--square"),
|
|
2014
2527
|
children: [/* @__PURE__ */ jsxs("button", {
|
|
2015
2528
|
type: "button",
|
|
2016
2529
|
className: cls("emergency-panel__button", "emergency-panel__button--emergency"),
|
|
@@ -2373,32 +2886,6 @@ function EmergencyLoading() {
|
|
|
2373
2886
|
});
|
|
2374
2887
|
}
|
|
2375
2888
|
|
|
2376
|
-
// src/core/date.ts
|
|
2377
|
-
/**
|
|
2378
|
-
* Formats a timestamp as `h:mmam` or `h:mmpm` in local time, without a space
|
|
2379
|
-
* or leading zero.
|
|
2380
|
-
*/
|
|
2381
|
-
function formatShortTime(value, locale = "es") {
|
|
2382
|
-
if (value === null) return "";
|
|
2383
|
-
const date = value instanceof Date ? value : new Date(value);
|
|
2384
|
-
if (Number.isNaN(date.getTime())) return "";
|
|
2385
|
-
const parts = new Intl.DateTimeFormat(locale, {
|
|
2386
|
-
hour: "numeric",
|
|
2387
|
-
minute: "2-digit",
|
|
2388
|
-
hour12: true
|
|
2389
|
-
}).formatToParts(date);
|
|
2390
|
-
const hour = parts.find((part) => part.type === "hour")?.value;
|
|
2391
|
-
const minute = parts.find((part) => part.type === "minute")?.value;
|
|
2392
|
-
const dayPeriod = parts.find((part) => part.type === "dayPeriod")?.value;
|
|
2393
|
-
if (!hour || !minute) return "";
|
|
2394
|
-
return `${hour}:${minute}${normalizePeriod(dayPeriod)}`;
|
|
2395
|
-
}
|
|
2396
|
-
function normalizePeriod(dayPeriod) {
|
|
2397
|
-
if (!dayPeriod) return "";
|
|
2398
|
-
if (/^p/i.test(dayPeriod)) return "pm";
|
|
2399
|
-
return /^a/i.test(dayPeriod) ? "am" : "";
|
|
2400
|
-
}
|
|
2401
|
-
|
|
2402
2889
|
// src/react/components/StatusIcon/index.tsx
|
|
2403
2890
|
/**
|
|
2404
2891
|
* Explicit responder state model:
|
|
@@ -2559,23 +3046,9 @@ function formatRounds(rounds) {
|
|
|
2559
3046
|
return `${rounds} ${roundsUnit(rounds)}`;
|
|
2560
3047
|
}
|
|
2561
3048
|
|
|
2562
|
-
// src/react/screens/primary/data.ts
|
|
2563
|
-
/**
|
|
2564
|
-
* Derives the remaining alert rounds from available messages and designated
|
|
2565
|
-
* responders. Invalid or non-positive input collapses to the minimum of one
|
|
2566
|
-
* round instead of producing `Infinity`, `NaN` or a negative value.
|
|
2567
|
-
*/
|
|
2568
|
-
function calculateRounds(messages, responders) {
|
|
2569
|
-
if (!Number.isFinite(messages) || !Number.isFinite(responders)) return 1;
|
|
2570
|
-
const availableMessages = Math.floor(messages);
|
|
2571
|
-
const designatedResponders = Math.floor(responders);
|
|
2572
|
-
if (availableMessages <= 0 || designatedResponders <= 0) return 1;
|
|
2573
|
-
return Math.max(1, Math.floor(availableMessages / designatedResponders));
|
|
2574
|
-
}
|
|
2575
|
-
|
|
2576
3049
|
// src/react/screens/primary/Availability.tsx
|
|
2577
3050
|
function Availability({ onRecharge, onDetails }) {
|
|
2578
|
-
const rounds = calculateRounds(
|
|
3051
|
+
const rounds = calculateRounds(27, 3);
|
|
2579
3052
|
return /* @__PURE__ */ jsxs("section", {
|
|
2580
3053
|
className: cls("emergency-availability"),
|
|
2581
3054
|
"aria-label": primaryCopy.availabilityTitle,
|
|
@@ -2617,23 +3090,30 @@ function Availability({ onRecharge, onDetails }) {
|
|
|
2617
3090
|
|
|
2618
3091
|
// src/react/components/EmergencyBody/index.tsx
|
|
2619
3092
|
function EmergencyBody(props) {
|
|
2620
|
-
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;
|
|
2621
3094
|
const showingFeedback = geolocationError !== null || Boolean(activationError) || abortResult !== null || simulationResult !== null;
|
|
2622
3095
|
const idle = !active && !loading && !showingFeedback && error === null;
|
|
2623
3096
|
return /* @__PURE__ */ jsxs("div", {
|
|
2624
3097
|
className: cls("emergency-panel__body-split", idle && "emergency-panel__body-split--with-availability"),
|
|
2625
|
-
children: [idle ? /* @__PURE__ */
|
|
3098
|
+
children: [idle ? /* @__PURE__ */ jsx("div", {
|
|
2626
3099
|
className: cls("emergency-panel__availability-region"),
|
|
2627
3100
|
children: /* @__PURE__ */ jsx(Availability, {
|
|
2628
3101
|
onRecharge,
|
|
2629
3102
|
onDetails
|
|
2630
3103
|
})
|
|
2631
|
-
}), /* @__PURE__ */
|
|
2632
|
-
className: cls("emergency-
|
|
2633
|
-
"aria-hidden": "true"
|
|
2634
|
-
})] }) : null, /* @__PURE__ */ jsxs("div", {
|
|
2635
|
-
className: cls("emergency-panel__prompt-region"),
|
|
3104
|
+
}) : null, /* @__PURE__ */ jsxs("div", {
|
|
3105
|
+
className: cls("emergency-panel__prompt-region", idle && "emergency-panel__prompt-region--idle"),
|
|
2636
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,
|
|
2637
3117
|
!loading && !showingFeedback ? /* @__PURE__ */ jsx("div", {
|
|
2638
3118
|
className: cls("sos-img__container"),
|
|
2639
3119
|
id: "sos-img__container",
|
|
@@ -2677,12 +3157,12 @@ function PrimaryScreen(props) {
|
|
|
2677
3157
|
const { navigate } = useScreenNavigation();
|
|
2678
3158
|
const idle = !props.active && !props.loading && !props.feedbackVisible && props.error === null;
|
|
2679
3159
|
const needsContactPhone = props.contactPhone === null;
|
|
2680
|
-
return /* @__PURE__ */
|
|
3160
|
+
return /* @__PURE__ */ jsxs(EmergencyScreenLayout, {
|
|
2681
3161
|
screen: "primary",
|
|
2682
3162
|
titleId: props.titleId,
|
|
2683
|
-
|
|
3163
|
+
bodyClassName: idle ? "emergency-panel__body--primary" : void 0,
|
|
3164
|
+
header: idle ? null : /* @__PURE__ */ jsx(EmergencyHeader, {
|
|
2684
3165
|
titleId: props.titleId,
|
|
2685
|
-
variant: idle ? "close-only" : "default",
|
|
2686
3166
|
onClose: () => props.onClose("close")
|
|
2687
3167
|
}),
|
|
2688
3168
|
footer: /* @__PURE__ */ jsx(EmergencyFooter, {
|
|
@@ -2690,11 +3170,17 @@ function PrimaryScreen(props) {
|
|
|
2690
3170
|
busy: props.busy,
|
|
2691
3171
|
aborting: props.aborting,
|
|
2692
3172
|
feedbackVisible: props.feedbackVisible,
|
|
3173
|
+
square: idle,
|
|
2693
3174
|
onActivate: needsContactPhone ? () => navigate("pre-emergency") : props.onActivate,
|
|
2694
3175
|
onRequestAbort: props.onRequestAbort,
|
|
2695
3176
|
onRequestSimulation: props.onRequestSimulation
|
|
2696
3177
|
}),
|
|
2697
|
-
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, {
|
|
2698
3184
|
active: props.active,
|
|
2699
3185
|
responders: props.responders,
|
|
2700
3186
|
refreshing: props.refreshing,
|
|
@@ -2709,8 +3195,9 @@ function PrimaryScreen(props) {
|
|
|
2709
3195
|
onRetry: props.onRetry,
|
|
2710
3196
|
onDismissFeedback: props.onDismissFeedback,
|
|
2711
3197
|
onRecharge: () => navigate("pricing"),
|
|
2712
|
-
onDetails: () => navigate("details")
|
|
2713
|
-
|
|
3198
|
+
onDetails: () => navigate("details"),
|
|
3199
|
+
onClose: () => props.onClose("close")
|
|
3200
|
+
})]
|
|
2714
3201
|
});
|
|
2715
3202
|
}
|
|
2716
3203
|
|
|
@@ -2883,7 +3370,9 @@ const screenRegistry = {
|
|
|
2883
3370
|
primary: PrimaryScreen,
|
|
2884
3371
|
"pre-emergency": PreEmergencyScreen,
|
|
2885
3372
|
pricing: PricingScreen,
|
|
2886
|
-
details: DetailsScreen
|
|
3373
|
+
details: DetailsScreen,
|
|
3374
|
+
history: HistoryScreen,
|
|
3375
|
+
"message-detail": MessageDetailScreen
|
|
2887
3376
|
};
|
|
2888
3377
|
|
|
2889
3378
|
// src/react/components/EmergencyPanel/index.tsx
|