@sincpro/mobile 0.1.1 → 0.3.1

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.
Files changed (51) hide show
  1. package/README.md +831 -47
  2. package/dist/entrypoints/queue/printImage.subscriber.js +3 -3
  3. package/dist/entrypoints/ui/AppShell.d.ts +61 -0
  4. package/dist/entrypoints/ui/AppShell.js +72 -11
  5. package/dist/entrypoints/ui/common_provider.d.ts +6 -1
  6. package/dist/entrypoints/ui/common_provider.js +45 -1
  7. package/dist/entrypoints/ui/domain_switcher.js +5 -4
  8. package/dist/entrypoints/ui/theme.d.ts +8 -7
  9. package/dist/entrypoints/ui/theme.js +8 -7
  10. package/dist/index.d.ts +0 -1
  11. package/dist/index.js +0 -1
  12. package/dist/infrastructure/ui/ToastHost.d.ts +6 -1
  13. package/dist/infrastructure/ui/ToastHost.js +18 -9
  14. package/dist/services/printer.service.d.ts +6 -0
  15. package/dist/services/printer.service.js +36 -3
  16. package/dist/ui/components/atoms/DebugBanner.js +4 -8
  17. package/dist/ui/components/atoms/PrinterIcon.d.ts +4 -0
  18. package/dist/ui/components/atoms/PrinterIcon.js +4 -0
  19. package/dist/ui/components/atoms/index.d.ts +1 -0
  20. package/dist/ui/components/atoms/index.js +1 -0
  21. package/dist/ui/components/molecules/BluetoothDeviceSelectorModal.js +16 -10
  22. package/dist/ui/components/molecules/DeadLetterErrorBlock.js +3 -2
  23. package/dist/ui/components/molecules/EventTimelineItem.js +31 -33
  24. package/dist/ui/components/molecules/GeoPermissionCard.d.ts +8 -0
  25. package/dist/ui/components/molecules/GeoPermissionCard.js +21 -0
  26. package/dist/ui/components/molecules/ProcessToast.d.ts +7 -4
  27. package/dist/ui/components/molecules/ProcessToast.js +45 -44
  28. package/dist/ui/components/molecules/ProcessToastProvider.js +1 -1
  29. package/dist/ui/components/molecules/TimeZoneSelector.d.ts +7 -0
  30. package/dist/ui/components/molecules/TimeZoneSelector.js +19 -0
  31. package/dist/ui/components/molecules/TimeZoneSelectorModal.d.ts +9 -0
  32. package/dist/ui/components/molecules/TimeZoneSelectorModal.js +61 -0
  33. package/dist/ui/components/molecules/index.d.ts +4 -0
  34. package/dist/ui/components/molecules/index.js +3 -0
  35. package/dist/ui/components/molecules/timezone.d.ts +4 -0
  36. package/dist/ui/components/molecules/timezone.js +1 -0
  37. package/dist/ui/components/organisms/BluetoothPrinterSelector.d.ts +3 -1
  38. package/dist/ui/components/organisms/BluetoothPrinterSelector.js +29 -9
  39. package/dist/ui/components/organisms/DatabaseInfoRow.js +1 -1
  40. package/dist/ui/components/organisms/DeadLetterQueueRow.js +3 -3
  41. package/dist/ui/components/organisms/EventRow.js +15 -15
  42. package/dist/ui/components/organisms/InjectableWebView.js +20 -10
  43. package/dist/ui/components/organisms/TableInfoInfoRow.js +1 -1
  44. package/dist/ui/screens/database/database.json_detail.js +3 -3
  45. package/dist/ui/screens/database/database.list.js +4 -5
  46. package/dist/ui/screens/database/database.table_rows.js +1 -2
  47. package/dist/ui/screens/dead_letter_queue/dead_letter_queue.list.js +4 -5
  48. package/dist/ui/screens/events/events.list.js +4 -5
  49. package/package.json +9 -5
  50. package/dist/ui/layouts/router_layouts.d.ts +0 -17
  51. package/dist/ui/layouts/router_layouts.js +0 -20
@@ -2,41 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
2
  import { EEventStatus } from "../../../domain/event_sourcing";
3
3
  import { Display } from "@sincpro/mobile-ui/Display";
4
4
  import CopyableText from "@sincpro/mobile-ui/Display/Display.CopyableText";
5
- import { theme } from "@sincpro/mobile-ui/theme";
5
+ import { useTheme } from "@sincpro/mobile-ui/theme";
6
6
  import { Typography } from "@sincpro/mobile-ui/Typography";
7
7
  import JsonPreview from "@sincpro/mobile-ui/widgets/JSONViewer";
8
8
  import { useState } from "react";
9
9
  import { TouchableOpacity, View } from "react-native";
10
- const statusColorMap = {
11
- [EEventStatus.ACKNOWLEDGED]: {
12
- bg: "bg-emerald-600",
13
- color: theme.success,
14
- light: `${theme.success}4D`,
15
- },
16
- [EEventStatus.PENDING]: {
17
- bg: "bg-amber-500",
18
- color: theme.warning,
19
- light: `${theme.warning}4D`,
20
- },
21
- [EEventStatus.PROCESSING]: {
22
- bg: "bg-accent",
23
- color: theme.warning,
24
- light: `${theme.warning}4D`,
25
- },
26
- [EEventStatus.FAILED]: {
27
- bg: "bg-red-500",
28
- color: theme.danger,
29
- light: `${theme.danger}4D`,
30
- },
31
- };
32
- const defaultStatus = {
33
- bg: "bg-gray-500",
34
- color: theme.text.secondary,
35
- light: `${theme.text.secondary}4D`,
36
- };
37
- function getStatusColor(status) {
38
- return statusColorMap[status] ?? defaultStatus;
39
- }
40
10
  function getStatusIcon(status) {
41
11
  switch (status) {
42
12
  case EEventStatus.ACKNOWLEDGED:
@@ -57,9 +27,37 @@ function formatEventName(name) {
57
27
  }
58
28
  function EventTimelineItem({ event, isLast = false }) {
59
29
  const [expanded, setExpanded] = useState(false);
60
- const statusInfo = getStatusColor(event.status);
30
+ const theme = useTheme();
31
+ const statusColorMap = {
32
+ [EEventStatus.ACKNOWLEDGED]: {
33
+ bg: "bg-success",
34
+ color: theme.success,
35
+ light: `${theme.success}4D`,
36
+ },
37
+ [EEventStatus.PENDING]: {
38
+ bg: "bg-warning",
39
+ color: theme.warning,
40
+ light: `${theme.warning}4D`,
41
+ },
42
+ [EEventStatus.PROCESSING]: {
43
+ bg: "bg-accent",
44
+ color: theme.warning,
45
+ light: `${theme.warning}4D`,
46
+ },
47
+ [EEventStatus.FAILED]: {
48
+ bg: "bg-danger",
49
+ color: theme.danger,
50
+ light: `${theme.danger}4D`,
51
+ },
52
+ };
53
+ const defaultStatus = {
54
+ bg: "bg-text-tertiary",
55
+ color: theme.text.secondary,
56
+ light: `${theme.text.secondary}4D`,
57
+ };
58
+ const statusInfo = statusColorMap[event.status] ?? defaultStatus;
61
59
  const statusIcon = getStatusIcon(event.status);
62
60
  const friendlyName = formatEventName(event.name);
63
- return (_jsxs(View, { className: "flex-row px-4", children: [_jsxs(View, { className: "items-center w-8 mr-3", children: [_jsx(View, { className: `w-6 h-6 rounded-full items-center justify-center ${statusInfo.bg}`, children: _jsx(Display.Icon, { color: "#ffffff", name: statusIcon, size: 12, type: "feather" }) }), !isLast && (_jsx(View, { className: "w-0.5 flex-1 mt-1", style: { backgroundColor: statusInfo.light } }))] }), _jsxs(TouchableOpacity, { activeOpacity: 0.7, className: "flex-1 bg-white rounded-xl p-3 mb-3 border border-gray-100 shadow-sm", onPress: () => setExpanded(!expanded), children: [_jsxs(View, { className: "flex-row justify-between items-center mb-2", children: [_jsx(Typography.Text, { semibold: true, variant: "body", children: friendlyName }), _jsx(Display.Icon, { color: theme.text.secondary, name: expanded ? "chevron-up" : "chevron-down", size: 16, type: "feather" })] }), _jsxs(View, { className: "flex-row items-center mb-1 gap-1.5", children: [_jsx(Display.Icon, { color: theme.text.secondary, name: "clock", size: 12, type: "feather" }), _jsx(Display.Date, { className: "text-text-tertiary", showTime: true, textVariant: "caption", value: event.createdAt })] }), _jsxs(View, { className: "flex-row items-center mb-1 gap-1.5", children: [_jsx(Display.Icon, { color: statusInfo.color, name: statusIcon, size: 12, type: "feather" }), _jsxs(Typography.Text, { style: { color: statusInfo.color }, variant: "caption", children: [event.status, " \u2022 Intentos: ", event.attempts] })] }), (event.sequence ?? 0) > 0 && (_jsxs(View, { className: "flex-row items-center mb-1 gap-1.5", children: [_jsx(Display.Icon, { color: theme.text.secondary, name: "hash", size: 12, type: "feather" }), _jsxs(Typography.Text, { className: "text-text-tertiary", variant: "caption", children: ["Secuencia: ", event.sequence] })] })), expanded && event && (_jsxs(View, { className: "mt-3 border-t border-gray-100 pt-3", children: [_jsxs(View, { className: "flex-row justify-between items-center mb-2", children: [_jsx(Typography.Text, { className: "text-text-tertiary", semibold: true, variant: "caption", children: "Payload" }), _jsx(CopyableText, { className: "text-primary text-xs", getValue: () => event.asJSON(true), label: "copy" })] }), _jsx(View, { className: "bg-gray-50 rounded-lg border border-gray-200 overflow-hidden", children: _jsx(JsonPreview, { selectedJson: event.asJSON(true) }) })] }))] })] }));
61
+ return (_jsxs(View, { className: "flex-row px-4", children: [_jsxs(View, { className: "items-center w-8 mr-3", children: [_jsx(View, { className: `w-6 h-6 rounded-full items-center justify-center ${statusInfo.bg}`, children: _jsx(Display.Icon, { color: "#ffffff", name: statusIcon, size: 12, type: "feather" }) }), !isLast && (_jsx(View, { className: "w-0.5 flex-1 mt-1", style: { backgroundColor: statusInfo.light } }))] }), _jsxs(TouchableOpacity, { activeOpacity: 0.7, className: "flex-1 bg-bg-card rounded-xl p-3 mb-3 border border-border-light shadow-sm", onPress: () => setExpanded(!expanded), children: [_jsxs(View, { className: "flex-row justify-between items-center mb-2", children: [_jsx(Typography.Text, { semibold: true, variant: "body", children: friendlyName }), _jsx(Display.Icon, { color: theme.text.secondary, name: expanded ? "chevron-up" : "chevron-down", size: 16, type: "feather" })] }), _jsxs(View, { className: "flex-row items-center mb-1 gap-1.5", children: [_jsx(Display.Icon, { color: theme.text.secondary, name: "clock", size: 12, type: "feather" }), _jsx(Display.Date, { className: "text-text-tertiary", showTime: true, textVariant: "caption", value: event.createdAt })] }), _jsxs(View, { className: "flex-row items-center mb-1 gap-1.5", children: [_jsx(Display.Icon, { color: statusInfo.color, name: statusIcon, size: 12, type: "feather" }), _jsxs(Typography.Text, { style: { color: statusInfo.color }, variant: "caption", children: [event.status, " \u2022 Intentos: ", event.attempts] })] }), (event.sequence ?? 0) > 0 && (_jsxs(View, { className: "flex-row items-center mb-1 gap-1.5", children: [_jsx(Display.Icon, { color: theme.text.secondary, name: "hash", size: 12, type: "feather" }), _jsxs(Typography.Text, { className: "text-text-tertiary", variant: "caption", children: ["Secuencia: ", event.sequence] })] })), expanded && event && (_jsxs(View, { className: "mt-3 border-t border-border-light pt-3", children: [_jsxs(View, { className: "flex-row justify-between items-center mb-2", children: [_jsx(Typography.Text, { className: "text-text-tertiary", semibold: true, variant: "caption", children: "Payload" }), _jsx(CopyableText, { className: "text-primary text-xs", getValue: () => event.asJSON(true), label: "copy" })] }), _jsx(View, { className: "bg-bg-muted rounded-lg border border-border-default overflow-hidden", children: _jsx(JsonPreview, { selectedJson: event.asJSON(true) }) })] }))] })] }));
64
62
  }
65
63
  export default EventTimelineItem;
@@ -0,0 +1,8 @@
1
+ interface GeoPermissionCardProps {
2
+ title: string;
3
+ hasPermission?: boolean;
4
+ loading?: boolean;
5
+ handleRequestPermission?: () => void;
6
+ }
7
+ declare function GeoPermissionCard({ title, loading, handleRequestPermission, hasPermission, }: GeoPermissionCardProps): import("react/jsx-runtime").JSX.Element;
8
+ export default GeoPermissionCard;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import { Display } from "@sincpro/mobile-ui/Display";
3
+ import { Form } from "@sincpro/mobile-ui/Form";
4
+ import { useTheme } from "@sincpro/mobile-ui/theme";
5
+ import { Typography } from "@sincpro/mobile-ui/Typography";
6
+ import { View } from "react-native";
7
+ import { tv } from "tailwind-variants";
8
+ const statusTextVariants = tv({
9
+ variants: {
10
+ granted: {
11
+ true: "text-success",
12
+ false: "text-danger",
13
+ },
14
+ },
15
+ });
16
+ function GeoPermissionCard({ title, loading, handleRequestPermission, hasPermission, }) {
17
+ const theme = useTheme();
18
+ const granted = hasPermission !== undefined ? hasPermission : false;
19
+ return (_jsx(Display.Card, { className: "my-2.5", children: _jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: granted ? theme.success : theme.danger, name: granted ? "check-circle" : "location-off", size: 35, type: "material" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: title }), _jsx(Typography.Text, { className: statusTextVariants({ granted }), children: granted ? "Permiso activo." : "Permiso inactivo." }), !granted && (_jsx(Form.Button, { loading: loading, onPress: handleRequestPermission, size: "small", title: "Abrir Configuración", variant: "cta" }))] })] }) }));
20
+ }
21
+ export default GeoPermissionCard;
@@ -1,5 +1,8 @@
1
- interface Props {
2
- position?: "top" | "bottom";
3
- }
4
- declare function ProcessToast({ position }: Props): import("react/jsx-runtime").JSX.Element | null;
1
+ /**
2
+ * Bridges the framework's queue/cron activity state (from CommonProvider) to the
3
+ * design-system Toast: a persistent `loading` toast while a queue/cron task runs, and a
4
+ * `danger` toast on failure. Renders nothing — the toast UI is owned by the DS
5
+ * `ToastProvider` (mounted in AppShell), so this must live inside it.
6
+ */
7
+ declare function ProcessToast(): null;
5
8
  export default ProcessToast;
@@ -1,51 +1,52 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
1
  import { useCommon } from "../../../entrypoints/ui/common_provider";
3
- import { Display } from "@sincpro/mobile-ui/Display";
4
- import { Feedback } from "@sincpro/mobile-ui/Feedback";
5
- import { theme } from "@sincpro/mobile-ui/theme";
6
- import { cn } from "@sincpro/mobile-ui/theme/tw";
7
- import { Typography } from "@sincpro/mobile-ui/Typography";
8
- import { useEffect, useState } from "react";
9
- import { Animated, Platform, TouchableOpacity, View } from "react-native";
10
- const Icon = Display.Icon;
11
- const Spinner = Feedback.Spinner;
12
- const Text = Typography.Text;
13
- function ProcessToast({ position = "top" }) {
14
- const { currentActivity, lastError, isProcessing, dismiss } = useCommon();
15
- const [slideAnim] = useState(new Animated.Value(-100));
16
- const [showError, setShowError] = useState(false);
2
+ import { useToast } from "@sincpro/mobile-ui/Feedback";
3
+ import { useEffect, useRef } from "react";
4
+ const MAX_ERROR_LEN = 150;
5
+ /**
6
+ * Bridges the framework's queue/cron activity state (from CommonProvider) to the
7
+ * design-system Toast: a persistent `loading` toast while a queue/cron task runs, and a
8
+ * `danger` toast on failure. Renders nothing — the toast UI is owned by the DS
9
+ * `ToastProvider` (mounted in AppShell), so this must live inside it.
10
+ */
11
+ function ProcessToast() {
12
+ const { currentActivity, lastError, isProcessing } = useCommon();
13
+ const toast = useToast();
14
+ const loadingIdRef = useRef(null);
15
+ const shownErrorRef = useRef(null);
17
16
  useEffect(() => {
18
- if (lastError)
19
- setShowError(true);
20
- }, [lastError]);
17
+ const showLoading = isProcessing && !lastError;
18
+ if (showLoading) {
19
+ const label = currentActivity?.label ?? "Sincronizando...";
20
+ if (loadingIdRef.current) {
21
+ toast.update(loadingIdRef.current, { message: label, variant: "loading" });
22
+ }
23
+ else {
24
+ loadingIdRef.current = toast.loading(label);
25
+ }
26
+ }
27
+ else if (loadingIdRef.current) {
28
+ toast.hide(loadingIdRef.current);
29
+ loadingIdRef.current = null;
30
+ }
31
+ }, [isProcessing, lastError, currentActivity, toast]);
21
32
  useEffect(() => {
22
- Animated.spring(slideAnim, {
23
- toValue: isProcessing ? 0 : position === "top" ? -100 : 100,
24
- tension: 300,
25
- friction: 25,
26
- useNativeDriver: true,
27
- }).start();
28
- }, [isProcessing, slideAnim, position]);
29
- function renderToast() {
30
- if (!isProcessing) {
31
- return null;
33
+ if (!lastError) {
34
+ shownErrorRef.current = null;
35
+ return;
32
36
  }
33
- const hasError = !!lastError;
34
- const activity = lastError || currentActivity;
35
- const label = activity?.label || "Sincronizando...";
36
- function handleDismiss() {
37
- setShowError(false);
38
- dismiss();
37
+ const key = `${lastError.id}:${lastError.error ?? ""}`;
38
+ if (shownErrorRef.current === key) {
39
+ return;
39
40
  }
40
- return (_jsx(Animated.View, { className: "absolute left-4 right-4 z-50 self-center", style: [
41
- position === "top"
42
- ? { top: Platform.OS === "ios" ? 100 : 60 }
43
- : { bottom: Platform.OS === "ios" ? 100 : 80 },
44
- { transform: [{ translateY: slideAnim }] },
45
- ], children: _jsxs(View, { className: cn("bg-white/[0.98] rounded-xl px-3.5 py-3 border-l-[3px] border-emerald-500 shadow-md", hasError && "bg-red-50/[0.98] border-red-500"), children: [_jsxs(View, { className: "flex-row items-center gap-3", children: [_jsx(View, { className: "w-5 h-5 justify-center items-center", children: hasError ? (_jsx(Icon, { color: theme.danger, name: "alert-circle", size: 16 })) : (_jsx(Spinner, { size: "small" })) }), _jsx(View, { className: "flex-1", children: _jsx(Text, { className: "text-gray-900 text-[13px] font-medium leading-4", variant: "captionSmall", children: hasError ? `Error: ${label}` : label }) }), _jsx(TouchableOpacity, { accessibilityLabel: "Cerrar notificación", className: "w-6 h-6 justify-center items-center rounded-full bg-gray-100", onPress: handleDismiss, children: _jsx(Icon, { color: theme.text.secondary, name: "close", size: 14 }) })] }), showError && lastError?.error && (_jsx(View, { className: "mt-2 pt-2 border-t border-gray-100", children: _jsx(Text, { className: "text-red-500 text-[11px] leading-[15px] font-mono", variant: "captionSmall", children: lastError.error.length > 150
46
- ? `${lastError.error.substring(0, 150)}...`
47
- : lastError.error }) }))] }) }));
48
- }
49
- return renderToast();
41
+ shownErrorRef.current = key;
42
+ const raw = lastError.error;
43
+ const detail = raw
44
+ ? raw.length > MAX_ERROR_LEN
45
+ ? `${raw.slice(0, MAX_ERROR_LEN)}...`
46
+ : raw
47
+ : undefined;
48
+ toast.danger(detail ?? lastError.label, { title: `Error: ${lastError.label}` });
49
+ }, [lastError, toast]);
50
+ return null;
50
51
  }
51
52
  export default ProcessToast;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
2
  import ProcessToast from "./ProcessToast";
3
3
  export function ProcessToastProvider({ children }) {
4
- return (_jsxs(_Fragment, { children: [children, _jsx(ProcessToast, { position: "top" })] }));
4
+ return (_jsxs(_Fragment, { children: [children, _jsx(ProcessToast, {})] }));
5
5
  }
@@ -0,0 +1,7 @@
1
+ import { TimezoneLocale } from "./timezone";
2
+ interface TimeZoneSelectorProps {
3
+ onSelect?: (tz: TimezoneLocale) => void;
4
+ timezone?: string | null;
5
+ }
6
+ export declare function TimeZoneSelector({ onSelect, timezone }: TimeZoneSelectorProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
2
+ import { Display, Form } from "@sincpro/mobile-ui/index";
3
+ import { theme } from "@sincpro/mobile-ui/theme/useTheme";
4
+ import { Typography } from "@sincpro/mobile-ui/Typography";
5
+ import { useState } from "react";
6
+ import { View } from "react-native";
7
+ import { TimeZoneSelectorModal } from "./TimeZoneSelectorModal";
8
+ export function TimeZoneSelector({ onSelect, timezone }) {
9
+ const [currentTimezone, setCurrentTimezone] = useState(timezone);
10
+ const [selectorVisible, setSelectorVisible] = useState(false);
11
+ function handleTimezoneSelected(tz) {
12
+ setCurrentTimezone(tz.timezone);
13
+ onSelect?.(tz);
14
+ }
15
+ const displayTimezone = currentTimezone
16
+ ? currentTimezone.replace(/_/g, " ").replace("America/", "")
17
+ : "No configurada";
18
+ return (_jsxs(Display.Card, { className: "my-2.5", children: [_jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: currentTimezone ? theme.info : theme.text.tertiary, name: "schedule", size: 35, type: "material" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: "Zona Horaria" }), currentTimezone ? (_jsxs(View, { className: "mt-2 bg-bg-card rounded-lg p-3", children: [_jsx(Typography.Text, { className: "text-text-primary", semibold: true, children: displayTimezone }), _jsx(Typography.Text, { className: "text-text-tertiary text-xs", children: currentTimezone }), _jsx(View, { className: "flex-row gap-2 mt-2", children: _jsx(Form.Button, { onPress: () => setSelectorVisible(true), size: "small", title: "Cambiar", variant: "outline" }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: "text-text-secondary mb-2", children: "Selecciona una zona horaria" }), _jsx(Form.Button, { onPress: () => setSelectorVisible(true), size: "small", title: "Seleccionar Zona Horaria", variant: "cta" })] }))] })] }), _jsx(TimeZoneSelectorModal, { currentTimezone: currentTimezone, onClose: () => setSelectorVisible(false), onSelect: handleTimezoneSelected, visible: selectorVisible })] }));
19
+ }
@@ -0,0 +1,9 @@
1
+ import { TimezoneLocale } from "./timezone";
2
+ interface TimeZoneSelectorModalProps {
3
+ visible: boolean;
4
+ onClose: () => void;
5
+ onSelect: (tz: TimezoneLocale) => void;
6
+ currentTimezone?: string | null;
7
+ }
8
+ declare function TimeZoneSelectorModal({ visible, onClose, onSelect, currentTimezone, }: TimeZoneSelectorModalProps): import("react/jsx-runtime").JSX.Element;
9
+ export { TimeZoneSelectorModal };
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import Sheet from "@sincpro/mobile-ui/Dialog/Sheet";
3
+ import { Display } from "@sincpro/mobile-ui/Display";
4
+ import { Form } from "@sincpro/mobile-ui/Form";
5
+ import { useTheme } from "@sincpro/mobile-ui/theme";
6
+ import { Typography } from "@sincpro/mobile-ui/Typography";
7
+ import { useMemo, useState } from "react";
8
+ import { TextInput, TouchableOpacity, View } from "react-native";
9
+ const TIMEZONES_LOCALES = {
10
+ bolivia: { timezone: "America/La_Paz", locale: "es-BO" },
11
+ costaRica: { timezone: "America/Costa_Rica", locale: "es-CR" },
12
+ guatemala: { timezone: "America/Guatemala", locale: "es-GT" },
13
+ argentina: { timezone: "America/Argentina/Buenos_Aires", locale: "es-AR" },
14
+ peru: { timezone: "America/Lima", locale: "es-PE" },
15
+ newYork: { timezone: "America/New_York", locale: "en-US" },
16
+ japon: { timezone: "Asia/Tokyo", locale: "ja-JP" },
17
+ };
18
+ function TimezoneRow({ item, isSelected, onSelect, }) {
19
+ const theme = useTheme();
20
+ return (_jsxs(TouchableOpacity, { activeOpacity: 0.7, className: `flex-row items-center p-4 rounded-xl ${isSelected ? "bg-bg-accent" : "bg-bg-card"}`, onPress: onSelect, children: [_jsx(Display.Icon, { color: isSelected ? theme.accent : theme.text.secondary, name: "schedule", size: 24, type: "material" }), _jsxs(View, { className: "ml-3 flex-1", children: [_jsx(Typography.Text, { semibold: true, children: item.label }), _jsx(Typography.Text, { className: "text-text-tertiary text-xs", children: item.locale })] }), isSelected && (_jsx(View, { className: "w-6 h-6 rounded-full bg-accent items-center justify-center", children: _jsx(Display.Icon, { color: theme.text.inverse, name: "check", size: 16, type: "material" }) }))] }));
21
+ }
22
+ function EmptyState() {
23
+ const theme = useTheme();
24
+ return (_jsxs(View, { className: "p-8 items-center justify-center", style: { minHeight: 200 }, children: [_jsx(Display.Icon, { color: theme.text.tertiary, name: "search-off", size: 48, type: "material" }), _jsx(Typography.Text, { className: "text-text-secondary text-center mt-4", children: "No se encontraron zonas horarias" })] }));
25
+ }
26
+ function TimeZoneSelectorModal({ visible, onClose, onSelect, currentTimezone, }) {
27
+ const theme = useTheme();
28
+ const [query, setQuery] = useState("");
29
+ const [selectedTimezone, setSelectedTimezone] = useState(currentTimezone || null);
30
+ const timezoneList = useMemo(() => {
31
+ return Object.values(TIMEZONES_LOCALES).map((tz) => ({
32
+ ...tz,
33
+ label: tz.timezone.replace(/_/g, " ").replace("America/", ""),
34
+ }));
35
+ }, []);
36
+ const filteredTimezones = useMemo(() => {
37
+ if (!query.trim())
38
+ return timezoneList;
39
+ const normalizedQuery = query
40
+ .toLowerCase()
41
+ .normalize("NFD")
42
+ .replace(/[\u0300-\u036f]/g, "");
43
+ return timezoneList.filter(({ label, timezone }) => {
44
+ const normalizedLabel = label
45
+ .toLowerCase()
46
+ .normalize("NFD")
47
+ .replace(/[\u0300-\u036f]/g, "");
48
+ const normalizedTz = timezone.toLowerCase();
49
+ return (normalizedLabel.includes(normalizedQuery) || normalizedTz.includes(normalizedQuery));
50
+ });
51
+ }, [query, timezoneList]);
52
+ function handleConfirm() {
53
+ const selected = timezoneList.find((tz) => tz.timezone === selectedTimezone);
54
+ if (selected) {
55
+ onSelect({ timezone: selected.timezone, locale: selected.locale });
56
+ onClose();
57
+ }
58
+ }
59
+ return (_jsxs(Sheet, { onClose: onClose, title: "Zona Horaria", visible: visible, children: [_jsx(Typography.Text, { className: "text-text-secondary text-xs mb-3", children: "Selecciona tu zona horaria" }), _jsx(TextInput, { className: "bg-bg-muted px-4 py-3 rounded-xl mb-2", onChangeText: setQuery, placeholder: "Buscar zona horaria...", placeholderTextColor: theme.text.tertiary, value: query }), filteredTimezones.length === 0 ? (_jsx(EmptyState, {})) : (_jsx(View, { className: "gap-1", children: filteredTimezones.map((item) => (_jsx(TimezoneRow, { isSelected: selectedTimezone === item.timezone, item: item, onSelect: () => setSelectedTimezone(item.timezone) }, item.timezone))) })), _jsxs(View, { className: "flex-row gap-2 mt-4", children: [_jsx(View, { className: "flex-1", children: _jsx(Form.Button, { onPress: onClose, title: "Cancelar", variant: "outline" }) }), selectedTimezone ? (_jsx(View, { className: "flex-1", children: _jsx(Form.Button, { onPress: handleConfirm, title: "Confirmar", variant: "cta" }) })) : null] })] }));
60
+ }
61
+ export { TimeZoneSelectorModal };
@@ -1,5 +1,9 @@
1
1
  export { BluetoothDeviceSelectorModal } from "./BluetoothDeviceSelectorModal";
2
2
  export { default as DeadLetterErrorBlock } from "./DeadLetterErrorBlock";
3
3
  export { default as EventTimelineItem } from "./EventTimelineItem";
4
+ export { default as GeoPermissionCard } from "./GeoPermissionCard";
4
5
  export { default as ProcessToast } from "./ProcessToast";
5
6
  export { ProcessToastProvider } from "./ProcessToastProvider";
7
+ export type { TimezoneLocale } from "./timezone";
8
+ export { TimeZoneSelector } from "./TimeZoneSelector";
9
+ export { TimeZoneSelectorModal } from "./TimeZoneSelectorModal";
@@ -1,5 +1,8 @@
1
1
  export { BluetoothDeviceSelectorModal } from "./BluetoothDeviceSelectorModal";
2
2
  export { default as DeadLetterErrorBlock } from "./DeadLetterErrorBlock";
3
3
  export { default as EventTimelineItem } from "./EventTimelineItem";
4
+ export { default as GeoPermissionCard } from "./GeoPermissionCard";
4
5
  export { default as ProcessToast } from "./ProcessToast";
5
6
  export { ProcessToastProvider } from "./ProcessToastProvider";
7
+ export { TimeZoneSelector } from "./TimeZoneSelector";
8
+ export { TimeZoneSelectorModal } from "./TimeZoneSelectorModal";
@@ -0,0 +1,4 @@
1
+ export interface TimezoneLocale {
2
+ timezone: string;
3
+ locale: string;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,6 +2,8 @@ import { ISelectedPrinter } from "../../../domain/print";
2
2
  interface BluetoothPrinterSelectorProps {
3
3
  onPrinterSelected?: (printer: ISelectedPrinter) => void;
4
4
  onConnectionChange?: (isConnected: boolean) => void;
5
+ /** Render as section rows (no outer card) — use inside FormViewV2.Content.Section. */
6
+ compact?: boolean;
5
7
  }
6
- declare function BluetoothPrinterSelector({ onPrinterSelected, onConnectionChange, }: BluetoothPrinterSelectorProps): import("react/jsx-runtime").JSX.Element;
8
+ declare function BluetoothPrinterSelector({ onPrinterSelected, onConnectionChange, compact, }: BluetoothPrinterSelectorProps): import("react/jsx-runtime").JSX.Element;
7
9
  export { BluetoothPrinterSelector };
@@ -1,9 +1,11 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
2
  import { bluetoothService } from "../../../services/bluetooth.service";
3
3
  import { printerService } from "../../../services/printer.service";
4
+ import PrinterIcon from "../../../ui/components/atoms/PrinterIcon";
4
5
  import { BluetoothDeviceSelectorModal } from "../../../ui/components/molecules/BluetoothDeviceSelectorModal";
5
- import { Display, Form } from "@sincpro/mobile-ui";
6
- import PrinterIcon from "@sincpro/mobile-ui/icons/PrinterIcon";
6
+ import { Display } from "@sincpro/mobile-ui/Display";
7
+ import { Form } from "@sincpro/mobile-ui/Form";
8
+ import { useTheme } from "@sincpro/mobile-ui/theme";
7
9
  import { Typography } from "@sincpro/mobile-ui/Typography";
8
10
  import { useCallback, useEffect, useState } from "react";
9
11
  import { View } from "react-native";
@@ -11,21 +13,22 @@ import { tv } from "tailwind-variants";
11
13
  const statusTextVariants = tv({
12
14
  variants: {
13
15
  granted: {
14
- true: "text-green-600",
15
- false: "text-red-500",
16
+ true: "text-success",
17
+ false: "text-danger",
16
18
  },
17
19
  },
18
20
  });
19
21
  function PermissionRequired({ loading, onRequestPermission, }) {
20
- return (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: statusTextVariants({ granted: false }), children: "Permiso de Bluetooth requerido" }), _jsx(Form.Button, { loading: loading, onPress: onRequestPermission, size: "small", title: "Solicitar Permiso" })] }));
22
+ return (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: statusTextVariants({ granted: false }), children: "Permiso de Bluetooth requerido" }), _jsx(Form.Button, { loading: loading, onPress: onRequestPermission, size: "small", title: "Solicitar Permiso", variant: "cta" })] }));
21
23
  }
22
24
  function PrinterInfo({ printer, isConnected, loading, onConnect, onTestPrint, onChangePrinter, }) {
23
- return (_jsxs(View, { className: "mt-2 bg-white rounded-lg p-3", children: [_jsx(Typography.Text, { className: "text-gray-700", semibold: true, children: printer.name }), _jsx(Typography.Text, { className: "text-gray-400 text-xs", children: printer.address }), _jsxs(View, { className: "flex-row gap-2 mt-2", children: [!isConnected ? (_jsx(Form.Button, { loading: loading, onPress: onConnect, size: "small", title: "Conectar", variant: "primary" })) : (_jsx(Form.Button, { loading: loading, onPress: onTestPrint, size: "small", title: "Imprimir Prueba", variant: "secondary" })), _jsx(Form.Button, { onPress: onChangePrinter, size: "small", title: "Cambiar", variant: "outline" })] }), isConnected && (_jsxs(View, { className: "flex-row items-center mt-2", children: [_jsx(View, { className: "w-2 h-2 rounded-full bg-green-500 mr-2" }), _jsx(Typography.Text, { className: "text-green-600 text-xs", children: "Conectado" })] }))] }));
25
+ return (_jsxs(View, { className: "mt-2 bg-bg-muted rounded-lg p-3", children: [_jsx(Typography.Text, { className: "text-text-primary", semibold: true, children: printer.name }), _jsx(Typography.Text, { className: "text-text-tertiary text-xs", children: printer.address }), _jsxs(View, { className: "flex-row gap-2 mt-2", children: [!isConnected ? (_jsx(Form.Button, { loading: loading, onPress: onConnect, size: "small", title: "Conectar", variant: "cta" })) : (_jsx(Form.Button, { loading: loading, onPress: onTestPrint, size: "small", title: "Imprimir Prueba", variant: "secondary" })), _jsx(Form.Button, { onPress: onChangePrinter, size: "small", title: "Cambiar", variant: "outline" })] }), isConnected && (_jsxs(View, { className: "flex-row items-center mt-2", children: [_jsx(View, { className: "w-2 h-2 rounded-full bg-success mr-2" }), _jsx(Typography.Text, { className: "text-success text-xs", children: "Conectado" })] }))] }));
24
26
  }
25
27
  function NoPrinterSelected({ loading, onSelectPrinter, }) {
26
- return (_jsx(Form.Button, { loading: loading, onPress: onSelectPrinter, size: "small", title: "Seleccionar Impresora" }));
28
+ return (_jsx(Form.Button, { loading: loading, onPress: onSelectPrinter, size: "small", title: "Seleccionar Impresora", variant: "cta" }));
27
29
  }
28
- function BluetoothPrinterSelector({ onPrinterSelected, onConnectionChange, }) {
30
+ function BluetoothPrinterSelector({ onPrinterSelected, onConnectionChange, compact = false, }) {
31
+ const theme = useTheme();
29
32
  const [hasPermission, setHasPermission] = useState(null);
30
33
  const [selectedPrinter, setSelectedPrinter] = useState(null);
31
34
  const [isConnected, setIsConnected] = useState(false);
@@ -87,6 +90,23 @@ function BluetoothPrinterSelector({ onPrinterSelected, onConnectionChange, }) {
87
90
  onPrinterSelected?.(printer);
88
91
  }
89
92
  const granted = hasPermission === true;
90
- return (_jsxs(View, { className: "bg-slate-50 rounded-xl p-5 my-2.5 shadow-sm", children: [_jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: granted ? "#22c55e" : "#ef4444", customIcon: PrinterIcon, size: 35, type: "custom" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: "Impresora Bluetooth" }), hasPermission === null ? (_jsx(Typography.Text, { className: "text-gray-500", children: "Verificando permisos..." })) : !granted ? (_jsx(PermissionRequired, { loading: loading, onRequestPermission: handleRequestPermission })) : (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: statusTextVariants({ granted: true }), children: "Bluetooth habilitado" }), selectedPrinter ? (_jsx(PrinterInfo, { isConnected: isConnected, loading: loading, onChangePrinter: () => setSelectorVisible(true), onConnect: handleConnect, onTestPrint: handleTestPrint, printer: selectedPrinter })) : (_jsx(NoPrinterSelected, { loading: loading, onSelectPrinter: () => setSelectorVisible(true) }))] }))] })] }), _jsx(BluetoothDeviceSelectorModal, { onClose: () => setSelectorVisible(false), onSelect: handleDeviceSelected, visible: selectorVisible })] }));
93
+ const modal = (_jsx(BluetoothDeviceSelectorModal, { onClose: () => setSelectorVisible(false), onSelect: handleDeviceSelected, visible: selectorVisible }));
94
+ if (compact) {
95
+ if (hasPermission === null) {
96
+ return (_jsxs(_Fragment, { children: [_jsx(Display.MenuButton, { description: "Verificando permisos...", icon: PrinterIcon, label: "Impresora Bluetooth", showDivider: false }), modal] }));
97
+ }
98
+ if (!granted) {
99
+ return (_jsxs(_Fragment, { children: [_jsx(Display.MenuButton, { description: "Permiso de Bluetooth requerido", icon: PrinterIcon, label: "Impresora Bluetooth", onPress: handleRequestPermission, showDivider: false }), modal] }));
100
+ }
101
+ if (!selectedPrinter) {
102
+ return (_jsxs(_Fragment, { children: [_jsx(Display.MenuButton, { description: "No configurada", icon: PrinterIcon, label: "Impresora Bluetooth", onPress: () => setSelectorVisible(true), showDivider: false }), modal] }));
103
+ }
104
+ return (_jsxs(_Fragment, { children: [_jsx(Display.MenuButton, { description: loading
105
+ ? "Conectando..."
106
+ : isConnected
107
+ ? "Conectado"
108
+ : "Sin conexión — toca para conectar", icon: PrinterIcon, label: selectedPrinter.name, onPress: !isConnected && !loading ? handleConnect : undefined }), _jsx(Display.MenuButton, { description: "Seleccionar otro dispositivo", icon: PrinterIcon, label: "Cambiar impresora", onPress: () => setSelectorVisible(true), showDivider: false }), modal] }));
109
+ }
110
+ return (_jsxs(Display.Card, { className: "my-2.5", children: [_jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: granted ? theme.success : theme.danger, customIcon: PrinterIcon, size: 35, type: "custom" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: "Impresora Bluetooth" }), hasPermission === null ? (_jsx(Typography.Text, { className: "text-text-secondary", children: "Verificando permisos..." })) : !granted ? (_jsx(PermissionRequired, { loading: loading, onRequestPermission: handleRequestPermission })) : (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: statusTextVariants({ granted: true }), children: "Bluetooth habilitado" }), selectedPrinter ? (_jsx(PrinterInfo, { isConnected: isConnected, loading: loading, onChangePrinter: () => setSelectorVisible(true), onConnect: handleConnect, onTestPrint: handleTestPrint, printer: selectedPrinter })) : (_jsx(NoPrinterSelected, { loading: loading, onSelectPrinter: () => setSelectorVisible(true) }))] }))] })] }), _jsx(BluetoothDeviceSelectorModal, { onClose: () => setSelectorVisible(false), onSelect: handleDeviceSelected, visible: selectorVisible })] }));
91
111
  }
92
112
  export { BluetoothPrinterSelector };
@@ -3,6 +3,6 @@ import { Display } from "@sincpro/mobile-ui/Display";
3
3
  import { ListViewV2 } from "@sincpro/mobile-ui/views/ListViewV2";
4
4
  import { View } from "react-native";
5
5
  function DatabaseInfoRow({ item, onPress }) {
6
- return (_jsxs(ListViewV2.Content.Row, { onPress: onPress, children: [_jsx(ListViewV2.Content.Row.Avatar, { children: _jsx(View, { className: "justify-center items-center p-2 rounded-lg bg-gray-100", children: _jsx(Display.Icon, { name: "database", size: 32, type: "antdesign" }) }) }), _jsxs(ListViewV2.Content.Row.Content, { children: [_jsx(ListViewV2.Content.Row.Title, { numberOfLines: 2, children: item.name }), _jsx(ListViewV2.Content.Row.Subtitle, { children: item.description || "N/A" })] })] }));
6
+ return (_jsxs(ListViewV2.Content.Row, { onPress: onPress, children: [_jsx(ListViewV2.Content.Row.Avatar, { children: _jsx(View, { className: "justify-center items-center p-2 rounded-lg bg-bg-muted", children: _jsx(Display.Icon, { name: "database", size: 32, type: "antdesign" }) }) }), _jsxs(ListViewV2.Content.Row.Content, { children: [_jsx(ListViewV2.Content.Row.Title, { numberOfLines: 2, children: item.name }), _jsx(ListViewV2.Content.Row.Subtitle, { children: item.description || "N/A" })] })] }));
7
7
  }
8
8
  export default DatabaseInfoRow;
@@ -54,19 +54,19 @@ function DeadLetterQueueRow({ item, onRetry }) {
54
54
  return (_jsxs(View, { className: "flex-row items-start mb-2", children: [_jsxs(View, { className: "flex-1 pr-2", children: [_jsx(Typography.Text, { className: "mb-1", numberOfLines: 2, semibold: true, variant: "body", children: friendlyName }), _jsx(Display.CopyableText, { value: event.name })] }), _jsx(View, { className: "ml-2 self-start", children: renderBadges() })] }));
55
55
  }
56
56
  function renderMeta() {
57
- return (_jsxs(View, { className: "flex-row items-center justify-between mb-3", children: [_jsx(Display.Date, { className: "text-gray-800", showTime: true, textVariant: "bodySmall", value: event.createdAt }), _jsx(Display.CopyableText, { label: "Copiar UUID", value: event.uuid })] }));
57
+ return (_jsxs(View, { className: "flex-row items-center justify-between mb-3", children: [_jsx(Display.Date, { className: "text-text-primary", showTime: true, textVariant: "bodySmall", value: event.createdAt }), _jsx(Display.CopyableText, { label: "Copiar UUID", value: event.uuid })] }));
58
58
  }
59
59
  function renderPayload() {
60
60
  if (!showPayload) {
61
61
  return null;
62
62
  }
63
- return (_jsxs(View, { className: "bg-gray-50 rounded-lg p-2 border border-gray-200 mb-2.5", children: [_jsx(Typography.Text, { className: "text-gray-700 mb-1", semibold: true, variant: "bodySmall", children: "Payload" }), _jsx(JsonPreview, { selectedJson: event.asJSON(true) })] }));
63
+ return (_jsxs(View, { className: "bg-bg-muted rounded-lg p-2 border border-border-default mb-2.5", children: [_jsx(Typography.Text, { className: "text-text-primary mb-1", semibold: true, variant: "bodySmall", children: "Payload" }), _jsx(JsonPreview, { selectedJson: event.asJSON(true) })] }));
64
64
  }
65
65
  function renderActions() {
66
66
  return (_jsxs(View, { className: "mt-2 gap-2", children: [_jsx(Form.Button, { className: "w-full", onPress: () => setShowError((v) => !v), size: "small", title: showError ? "Ocultar error" : "Ver error", variant: "secondary" }), _jsx(Form.Button, { className: "w-full", onPress: togglePayload, size: "small", title: showPayload ? "Ocultar payload" : "Ver payload", variant: "secondary" }), _jsx(Form.Button, { className: "w-full", onPress: async () => {
67
67
  await Clipboard.setStringAsync(event.asJSON(true));
68
68
  }, size: "small", title: "Copiar payload", variant: "secondary" }), _jsx(Form.Button, { className: "w-full", disabled: sending, loading: sending, onPress: handleRetry, size: "medium", title: sending ? "Reintentando…" : "Reintentar", variant: "primary" })] }));
69
69
  }
70
- return (_jsxs(View, { className: "bg-white border border-gray-200 rounded-2xl mx-4 p-3.5 mb-3 shadow-sm", children: [renderHeader(), renderMeta(), _jsx(DeadLetterErrorBlock, { errorMessage: event.errorMessage, expanded: showError, onToggle: () => setShowError((v) => !v) }), renderPayload(), renderActions()] }));
70
+ return (_jsxs(View, { className: "bg-bg-card border border-border-default rounded-2xl mx-4 p-3.5 mb-3 shadow-sm", children: [renderHeader(), renderMeta(), _jsx(DeadLetterErrorBlock, { errorMessage: event.errorMessage, expanded: showError, onToggle: () => setShowError((v) => !v) }), renderPayload(), renderActions()] }));
71
71
  }
72
72
  export default DeadLetterQueueRow;
@@ -17,28 +17,28 @@ function EventRow({ item, onRetry }) {
17
17
  const statusBadge = (() => {
18
18
  if (item.status === EEventStatus.FAILED) {
19
19
  return {
20
- backgroundClass: "bg-red-100 border-red-200",
21
- textClass: "text-red-700",
20
+ backgroundClass: "bg-danger-light border-danger",
21
+ textClass: "text-danger",
22
22
  label: "FAILED",
23
23
  };
24
24
  }
25
25
  if (item.status === EEventStatus.ACKNOWLEDGED) {
26
26
  return {
27
- backgroundClass: "bg-green-100 border-green-200",
28
- textClass: "text-green-700",
27
+ backgroundClass: "bg-success-light border-success",
28
+ textClass: "text-success",
29
29
  label: "ACKNOWLEDGED",
30
30
  };
31
31
  }
32
32
  if (item.status === EEventStatus.PENDING || item.status === EEventStatus.PROCESSING) {
33
33
  return {
34
- backgroundClass: "bg-blue-100 border-blue-200",
35
- textClass: "text-blue-700",
34
+ backgroundClass: "bg-info-light border-info",
35
+ textClass: "text-info",
36
36
  label: item.status,
37
37
  };
38
38
  }
39
39
  return {
40
- backgroundClass: "bg-gray-100 border-gray-200",
41
- textClass: "text-gray-700",
40
+ backgroundClass: "bg-bg-muted border-border-default",
41
+ textClass: "text-text-primary",
42
42
  label: item.status,
43
43
  };
44
44
  })();
@@ -54,15 +54,15 @@ function EventRow({ item, onRetry }) {
54
54
  }
55
55
  };
56
56
  function renderMeta() {
57
- return (_jsxs(View, { className: "flex-row items-center justify-between mb-3", children: [_jsx(Display.Date, { className: "text-gray-800", showTime: true, textVariant: "bodySmall", value: item.createdAt }), _jsx(Display.CopyableText, { label: "Copiar UUID", value: item.uuid })] }));
57
+ return (_jsxs(View, { className: "flex-row items-center justify-between mb-3", children: [_jsx(Display.Date, { className: "text-text-primary", showTime: true, textVariant: "bodySmall", value: item.createdAt }), _jsx(Display.CopyableText, { label: "Copiar UUID", value: item.uuid })] }));
58
58
  }
59
59
  function renderBadges() {
60
60
  const badges = [];
61
61
  const statusVariantMap = {
62
- "bg-red-100 border-red-200": "danger",
63
- "bg-green-100 border-green-200": "successDark",
64
- "bg-blue-100 border-blue-200": "infoDark",
65
- "bg-gray-100 border-gray-200": "warning",
62
+ "bg-danger-light border-danger": "danger",
63
+ "bg-success-light border-success": "successDark",
64
+ "bg-info-light border-info": "infoDark",
65
+ "bg-bg-muted border-border-default": "warning",
66
66
  };
67
67
  const variant = statusVariantMap[statusBadge.backgroundClass] || "info";
68
68
  badges.push(_jsx(Display.Badge, { className: "self-end", label: statusBadge.label, variant: variant }, "status"));
@@ -78,13 +78,13 @@ function EventRow({ item, onRetry }) {
78
78
  if (!showPayload) {
79
79
  return null;
80
80
  }
81
- return (_jsxs(View, { className: "bg-gray-50 rounded-lg p-2 border border-gray-200 mb-2", children: [_jsx(Typography.Text, { className: "text-gray-700 mb-1", semibold: true, variant: "bodySmall", children: "Payload" }), _jsx(JsonPreview, { selectedJson: payloadString })] }));
81
+ return (_jsxs(View, { className: "bg-bg-muted rounded-lg p-2 border border-border-default mb-2", children: [_jsx(Typography.Text, { className: "text-text-primary mb-1", semibold: true, variant: "bodySmall", children: "Payload" }), _jsx(JsonPreview, { selectedJson: payloadString })] }));
82
82
  }
83
83
  function renderActions() {
84
84
  return (_jsxs(View, { className: "mt-2 gap-2", children: [_jsx(Form.Button, { className: "w-full", onPress: () => setShowPayload((v) => !v), size: "small", title: showPayload ? "Ocultar payload" : "Ver payload", variant: "secondary" }), _jsx(Form.Button, { className: "w-full", onPress: async () => {
85
85
  await Clipboard.setStringAsync(payloadString);
86
86
  }, size: "small", title: "Copiar payload", variant: "secondary" }), _jsx(Form.Button, { className: "w-full", disabled: sending, loading: sending, onPress: handleRetry, size: "medium", title: sending ? "Reenviando…" : "Re-disparar", variant: "primary" })] }));
87
87
  }
88
- return (_jsxs(View, { className: "bg-white border border-gray-200 rounded-2xl mx-4 p-3.5 mb-3 shadow-sm", children: [_jsxs(View, { className: "flex-row items-start mb-2", children: [_jsxs(View, { className: "flex-1 pr-2", children: [_jsx(Typography.Text, { className: "mb-1", numberOfLines: 2, semibold: true, variant: "body", children: friendlyName }), _jsx(Display.CopyableText, { value: item.name })] }), _jsx(View, { className: "ml-2 self-start", children: renderBadges() })] }), renderMeta(), renderPayload(), renderActions()] }));
88
+ return (_jsxs(View, { className: "bg-bg-card border border-border-default rounded-2xl mx-4 p-3.5 mb-3 shadow-sm", children: [_jsxs(View, { className: "flex-row items-start mb-2", children: [_jsxs(View, { className: "flex-1 pr-2", children: [_jsx(Typography.Text, { className: "mb-1", numberOfLines: 2, semibold: true, variant: "body", children: friendlyName }), _jsx(Display.CopyableText, { value: item.name })] }), _jsx(View, { className: "ml-2 self-start", children: renderBadges() })] }), renderMeta(), renderPayload(), renderActions()] }));
89
89
  }
90
90
  export default EventRow;