@sincpro/mobile 0.4.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/adapters/JsonSerializer.adapter.d.ts +1 -1
- package/dist/adapters/JsonSerializer.adapter.js +2 -2
- package/dist/adapters/ReceiptExporter.adapter.js +10 -2
- package/dist/adapters/repositories/database_table.repository.d.ts +3 -2
- package/dist/adapters/repositories/database_table.repository.js +1 -1
- package/dist/adapters/repositories/document.repository.d.ts +81 -0
- package/dist/adapters/repositories/document.repository.js +653 -0
- package/dist/adapters/repositories/domain_event.repository.d.ts +17 -17
- package/dist/adapters/repositories/domain_event.repository.js +25 -31
- package/dist/adapters/repositories/domain_event_dead_letter.repository.d.ts +10 -10
- package/dist/adapters/repositories/domain_event_dead_letter.repository.js +14 -13
- package/dist/adapters/repositories/event_row.d.ts +13 -0
- package/dist/adapters/repositories/event_row.js +22 -0
- package/dist/adapters/repositories/sqlite_document_store.d.ts +33 -0
- package/dist/adapters/repositories/sqlite_document_store.js +201 -0
- package/dist/domain/connectivity/events.d.ts +5 -5
- package/dist/domain/connectivity/events.js +3 -3
- package/dist/domain/database/criteria.d.ts +19 -0
- package/dist/domain/database/criteria.js +36 -0
- package/dist/domain/database/criteria_clock.d.ts +8 -0
- package/dist/domain/database/criteria_clock.js +305 -0
- package/dist/domain/database/criteria_sql.d.ts +61 -0
- package/dist/domain/database/criteria_sql.js +476 -0
- package/dist/domain/database/database.d.ts +1 -0
- package/dist/domain/database/index.d.ts +3 -1
- package/dist/domain/database/index.js +3 -1
- package/dist/domain/database/migration_plan.d.ts +14 -0
- package/dist/domain/database/migration_plan.js +44 -0
- package/dist/domain/entity/change_tracking.d.ts +21 -0
- package/dist/domain/entity/change_tracking.js +71 -0
- package/dist/domain/entity/checks.d.ts +8 -0
- package/dist/domain/entity/checks.js +82 -0
- package/dist/domain/entity/entity.d.ts +39 -32
- package/dist/domain/entity/entity.js +94 -105
- package/dist/domain/entity/entity_collection.d.ts +15 -30
- package/dist/domain/entity/entity_collection.js +30 -121
- package/dist/domain/entity/index.d.ts +5 -0
- package/dist/domain/entity/index.js +5 -0
- package/dist/domain/entity/reconcile.d.ts +7 -0
- package/dist/domain/entity/reconcile.js +12 -0
- package/dist/domain/entity/relations.d.ts +27 -0
- package/dist/domain/entity/relations.js +69 -0
- package/dist/domain/entity/remote_sync.d.ts +4 -0
- package/dist/domain/entity/remote_sync.js +19 -0
- package/dist/domain/entity/values.d.ts +6 -0
- package/dist/domain/entity/values.js +13 -0
- package/dist/domain/events/catalog.d.ts +29 -0
- package/dist/domain/{events.js → events/catalog.js} +7 -11
- package/dist/domain/events/chain.d.ts +5 -0
- package/dist/domain/events/chain.js +6 -0
- package/dist/domain/{event_sourcing → events}/domain_event.d.ts +20 -22
- package/dist/domain/events/domain_event.js +227 -0
- package/dist/domain/events/index.d.ts +8 -0
- package/dist/domain/events/index.js +8 -0
- package/dist/domain/events/integration_event.d.ts +103 -0
- package/dist/domain/events/integration_event.js +72 -0
- package/dist/domain/events/label.d.ts +2 -0
- package/dist/domain/events/label.js +26 -0
- package/dist/domain/index.d.ts +0 -1
- package/dist/domain/index.js +0 -1
- package/dist/domain/print/events.d.ts +8 -4
- package/dist/domain/print/events.js +9 -4
- package/dist/domain/repositories/document_store.d.ts +33 -0
- package/dist/domain/repositories/document_store.js +5 -0
- package/dist/domain/repositories/hooks.d.ts +23 -0
- package/dist/domain/repositories/hooks.js +32 -0
- package/dist/domain/repositories/index.d.ts +4 -0
- package/dist/domain/repositories/index.js +4 -0
- package/dist/domain/{database → repositories}/repository.d.ts +9 -3
- package/dist/domain/settings.d.ts +4 -1
- package/dist/domain/settings.js +3 -0
- package/dist/domain/webview/events.d.ts +2 -2
- package/dist/domain/webview/events.js +2 -2
- package/dist/entrypoints/db/migrations.js +10 -10
- package/dist/entrypoints/queue/QueueProcessor.d.ts +1 -1
- package/dist/entrypoints/queue/activateDomain.subscriber.d.ts +2 -2
- package/dist/entrypoints/queue/activateDomain.subscriber.js +2 -2
- package/dist/entrypoints/queue/newAppSettings.handler.d.ts +2 -2
- package/dist/entrypoints/queue/newAppSettings.handler.js +1 -1
- package/dist/entrypoints/queue/printImage.subscriber.d.ts +1 -1
- package/dist/entrypoints/queue/printImage.subscriber.js +2 -2
- package/dist/entrypoints/queue/processWebViewMessage.subscriber.d.ts +1 -1
- package/dist/entrypoints/queue/processWebViewMessage.subscriber.js +1 -1
- package/dist/entrypoints/ui/AppShell.js +2 -2
- package/dist/entrypoints/ui/common_provider.d.ts +1 -13
- package/dist/entrypoints/ui/common_provider.js +4 -133
- package/dist/entrypoints/ui/domain_switcher.d.ts +2 -2
- package/dist/event_driven/index.d.ts +1 -0
- package/dist/event_driven/index.js +1 -0
- package/dist/{domain/event_sourcing/event_handler.d.ts → event_driven/subscriber.d.ts} +1 -1
- package/dist/exceptions.d.ts +21 -0
- package/dist/exceptions.js +30 -0
- package/dist/framework/base_module.d.ts +1 -1
- package/dist/framework/createApp.d.ts +3 -3
- package/dist/framework/domain_module.d.ts +1 -1
- package/dist/framework/feature.d.ts +26 -0
- package/dist/framework/feature.js +36 -0
- package/dist/framework/kernel.d.ts +1 -1
- package/dist/framework/kernel.js +17 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/infrastructure/database/connector.d.ts +2 -0
- package/dist/infrastructure/database/connector.js +22 -0
- package/dist/infrastructure/database/index.d.ts +1 -0
- package/dist/infrastructure/database/index.js +1 -0
- package/dist/infrastructure/database/schema.d.ts +9 -0
- package/dist/infrastructure/database/schema.js +61 -0
- package/dist/infrastructure/database/utils.d.ts +2 -0
- package/dist/infrastructure/database/utils.js +12 -4
- package/dist/infrastructure/event_chain.d.ts +6 -0
- package/dist/infrastructure/event_chain.js +25 -0
- package/dist/infrastructure/interceptor/intercept.d.ts +7 -2
- package/dist/infrastructure/interceptor/intercept.js +5 -2
- package/dist/infrastructure/telemetry/tracing/tracing_hooks.d.ts +9 -6
- package/dist/infrastructure/telemetry/tracing/tracing_hooks.js +61 -35
- package/dist/infrastructure/ui/UIEventBus.d.ts +3 -1
- package/dist/infrastructure/ui/UIEventBus.js +8 -1
- package/dist/infrastructure/ui/activity.d.ts +37 -0
- package/dist/infrastructure/ui/activity.js +84 -0
- package/dist/infrastructure/workers/CronWorker.d.ts +6 -4
- package/dist/infrastructure/workers/CronWorker.js +24 -18
- package/dist/infrastructure/workers/EventBus.d.ts +9 -5
- package/dist/infrastructure/workers/EventBus.js +68 -33
- package/dist/services/bluetooth.service.js +16 -14
- package/dist/services/dead_letter_queue.service.d.ts +7 -7
- package/dist/services/dead_letter_queue.service.js +0 -2
- package/dist/services/event.service.d.ts +3 -3
- package/dist/services/event.service.js +1 -1
- package/dist/services/network.service.d.ts +1 -1
- package/dist/services/network.service.js +17 -15
- package/dist/services/printer.service.d.ts +1 -1
- package/dist/services/printer.service.js +50 -44
- package/dist/tools/utils/date.js +4 -3
- package/dist/tools/utils/monetary.d.ts +6 -3
- package/dist/tools/utils/monetary.js +33 -21
- package/dist/tools/utils/serializer.d.ts +1 -1
- package/dist/tools/utils/serializer.js +32 -35
- package/dist/ui/activity/DeviceNotices.d.ts +1 -0
- package/dist/ui/activity/DeviceNotices.js +29 -0
- package/dist/ui/activity/ProcessToast.d.ts +2 -0
- package/dist/ui/activity/ProcessToast.js +71 -0
- package/dist/ui/{components/molecules → activity}/ProcessToastProvider.d.ts +1 -1
- package/dist/ui/activity/index.d.ts +4 -0
- package/dist/ui/activity/index.js +4 -0
- package/dist/ui/activity/useActivity.d.ts +9 -0
- package/dist/ui/activity/useActivity.js +48 -0
- package/dist/ui/components/atoms/DebugBanner.d.ts +1 -1
- package/dist/ui/components/molecules/BluetoothDeviceSelectorModal.d.ts +1 -1
- package/dist/ui/components/molecules/BluetoothDeviceSelectorModal.js +8 -2
- package/dist/ui/components/molecules/DeadLetterErrorBlock.d.ts +1 -1
- package/dist/ui/components/molecules/EventTimelineItem.d.ts +3 -3
- package/dist/ui/components/molecules/EventTimelineItem.js +1 -1
- package/dist/ui/components/molecules/GeoPermissionCard.d.ts +1 -1
- package/dist/ui/components/molecules/TimeZoneSelector.d.ts +1 -1
- package/dist/ui/components/molecules/TimeZoneSelectorModal.d.ts +1 -1
- package/dist/ui/components/molecules/TimeZoneSelectorModal.js +5 -3
- package/dist/ui/components/molecules/index.d.ts +1 -2
- package/dist/ui/components/molecules/index.js +1 -2
- package/dist/ui/components/organisms/BluetoothPrinterSelector.d.ts +1 -1
- package/dist/ui/components/organisms/BluetoothPrinterSelector.js +3 -0
- package/dist/ui/components/organisms/DatabaseInfoRow.d.ts +1 -1
- package/dist/ui/components/organisms/DeadLetterQueueRow.d.ts +5 -4
- package/dist/ui/components/organisms/EventRow.d.ts +4 -4
- package/dist/ui/components/organisms/EventRow.js +1 -1
- package/dist/ui/components/organisms/InjectableWebView.d.ts +2 -2
- package/dist/ui/components/organisms/InjectableWebView.js +6 -3
- package/dist/ui/components/organisms/Receipt.d.ts +2 -1
- package/dist/ui/components/organisms/TableInfoInfoRow.d.ts +1 -1
- package/dist/ui/screens/database/database.context.d.ts +2 -2
- package/dist/ui/screens/database/database.context.js +9 -18
- package/dist/ui/screens/database/database.json_detail.d.ts +1 -1
- package/dist/ui/screens/database/database.list.d.ts +1 -1
- package/dist/ui/screens/database/database.table_rows.d.ts +1 -1
- package/dist/ui/screens/dead_letter_queue/dead_letter_queue.context.d.ts +7 -7
- package/dist/ui/screens/dead_letter_queue/dead_letter_queue.list.d.ts +1 -1
- package/dist/ui/screens/events/events.context.d.ts +6 -6
- package/dist/ui/screens/events/events.context.js +20 -25
- package/dist/ui/screens/events/events.list.d.ts +1 -1
- package/package.json +51 -40
- package/dist/domain/event_sourcing/domain_event.js +0 -164
- package/dist/domain/event_sourcing/event.d.ts +0 -25
- package/dist/domain/event_sourcing/event.js +0 -25
- package/dist/domain/event_sourcing/index.d.ts +0 -2
- package/dist/domain/event_sourcing/index.js +0 -2
- package/dist/domain/events.d.ts +0 -33
- package/dist/infrastructure/ui/ToastHost.d.ts +0 -6
- package/dist/infrastructure/ui/ToastHost.js +0 -28
- package/dist/infrastructure/ui/events.d.ts +0 -1
- package/dist/infrastructure/ui/events.js +0 -1
- package/dist/ui/components/molecules/ProcessToast.d.ts +0 -8
- package/dist/ui/components/molecules/ProcessToast.js +0 -52
- /package/dist/domain/{repositories.d.ts → repositories/catalog.d.ts} +0 -0
- /package/dist/domain/{repositories.js → repositories/catalog.js} +0 -0
- /package/dist/domain/{database → repositories}/repository.js +0 -0
- /package/dist/{domain/event_sourcing/event_handler.js → event_driven/subscriber.js} +0 -0
- /package/dist/ui/{components/molecules → activity}/ProcessToastProvider.js +0 -0
|
@@ -3,8 +3,7 @@ import { SettingsRepository } from "../adapters/repositories/setting.repository"
|
|
|
3
3
|
import { getPrinterDriver, hasPrinterDriver, setPrinterDriver, } from "../domain/print";
|
|
4
4
|
import { ECommonSetting } from "../domain/settings";
|
|
5
5
|
import { loggerUseCases } from "../infrastructure/logger";
|
|
6
|
-
import {
|
|
7
|
-
import { UIEventBus } from "../infrastructure/ui/UIEventBus";
|
|
6
|
+
import { notifyDevice } from "../infrastructure/ui/activity";
|
|
8
7
|
import { File } from "expo-file-system";
|
|
9
8
|
import * as Print from "expo-print";
|
|
10
9
|
import { bluetoothService } from "./bluetooth.service";
|
|
@@ -26,7 +25,7 @@ class PrinterService {
|
|
|
26
25
|
isConnected() {
|
|
27
26
|
return getPrinterDriver().isConnected();
|
|
28
27
|
}
|
|
29
|
-
async connect(address, name) {
|
|
28
|
+
async connect(address, name, notify = true) {
|
|
30
29
|
const hasPermissions = await this.bluetooth.ensurePermissionsForPrinter();
|
|
31
30
|
if (!hasPermissions) {
|
|
32
31
|
return false;
|
|
@@ -39,30 +38,37 @@ class PrinterService {
|
|
|
39
38
|
selectedAt: new Date().toISOString(),
|
|
40
39
|
};
|
|
41
40
|
await this.saveSelectedPrinter(printer);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
if (notify) {
|
|
42
|
+
notifyDevice({
|
|
43
|
+
name: "printer.connected",
|
|
44
|
+
title: "Impresora conectada",
|
|
45
|
+
message: `Conectado a ${name}`,
|
|
46
|
+
variant: "success",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
47
49
|
return true;
|
|
48
50
|
}
|
|
49
51
|
catch (error) {
|
|
50
52
|
loggerUseCases.error(`Failed to connect to printer: ${name}`, error);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
if (notify) {
|
|
54
|
+
notifyDevice({
|
|
55
|
+
name: "printer.connect_failed",
|
|
56
|
+
title: "Error de conexión",
|
|
57
|
+
message: `No se pudo conectar a ${name}`,
|
|
58
|
+
variant: "danger",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
56
61
|
return false;
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
64
|
async disconnect() {
|
|
60
65
|
try {
|
|
61
66
|
await getPrinterDriver().disconnect();
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
notifyDevice({
|
|
68
|
+
name: "printer.disconnected",
|
|
69
|
+
title: "Desconectado",
|
|
70
|
+
message: "Impresora desconectada",
|
|
71
|
+
variant: "info",
|
|
66
72
|
});
|
|
67
73
|
}
|
|
68
74
|
catch (error) {
|
|
@@ -87,10 +93,11 @@ class PrinterService {
|
|
|
87
93
|
}
|
|
88
94
|
async printTestPage() {
|
|
89
95
|
if (!this.isConnected()) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
notifyDevice({
|
|
97
|
+
name: "printer.not_connected",
|
|
98
|
+
title: "Sin conexión",
|
|
99
|
+
message: "Conecta una impresora primero",
|
|
100
|
+
variant: "danger",
|
|
94
101
|
});
|
|
95
102
|
return false;
|
|
96
103
|
}
|
|
@@ -108,19 +115,21 @@ class PrinterService {
|
|
|
108
115
|
alignment: "center",
|
|
109
116
|
fontSize: "small",
|
|
110
117
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
118
|
+
notifyDevice({
|
|
119
|
+
name: "printer.test_ok",
|
|
120
|
+
title: "Impresión exitosa",
|
|
121
|
+
message: "Página de prueba impresa",
|
|
122
|
+
variant: "success",
|
|
115
123
|
});
|
|
116
124
|
return true;
|
|
117
125
|
}
|
|
118
126
|
catch (error) {
|
|
119
127
|
loggerUseCases.error("Error printing test page", error);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
notifyDevice({
|
|
129
|
+
name: "printer.test_failed",
|
|
130
|
+
title: "Error de impresión",
|
|
131
|
+
message: "No se pudo imprimir la página de prueba",
|
|
132
|
+
variant: "danger",
|
|
124
133
|
});
|
|
125
134
|
return false;
|
|
126
135
|
}
|
|
@@ -137,18 +146,13 @@ class PrinterService {
|
|
|
137
146
|
loggerUseCases.warn("Print failed — attempting grace reconnect", firstError);
|
|
138
147
|
const reconnected = await this.forceReconnect();
|
|
139
148
|
if (!reconnected)
|
|
140
|
-
return false;
|
|
149
|
+
return false;
|
|
141
150
|
try {
|
|
142
151
|
await getPrinterDriver().printImageBase64(base64Data);
|
|
143
152
|
return true;
|
|
144
153
|
}
|
|
145
154
|
catch (retryError) {
|
|
146
155
|
loggerUseCases.error("Print retry after reconnect also failed", retryError);
|
|
147
|
-
UIEventBus.emit(UI_NOTIFICATION_EVENT, {
|
|
148
|
-
type: "error",
|
|
149
|
-
text1: "Error de impresión",
|
|
150
|
-
text2: "No se pudo imprimir incluso tras reconectar la impresora",
|
|
151
|
-
});
|
|
152
156
|
return false;
|
|
153
157
|
}
|
|
154
158
|
}
|
|
@@ -164,10 +168,11 @@ class PrinterService {
|
|
|
164
168
|
return false;
|
|
165
169
|
}
|
|
166
170
|
await getPrinterDriver().printImageBase64(imageBase64);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
+
notifyDevice({
|
|
172
|
+
name: "printer.sent",
|
|
173
|
+
title: "Impresión enviada",
|
|
174
|
+
message: "Documento enviado a la impresora",
|
|
175
|
+
variant: "success",
|
|
171
176
|
});
|
|
172
177
|
return true;
|
|
173
178
|
}
|
|
@@ -233,7 +238,7 @@ class PrinterService {
|
|
|
233
238
|
if (!printer)
|
|
234
239
|
return false;
|
|
235
240
|
loggerUseCases.info(`Grace reconnect: reconnecting to ${printer.name} (${printer.address})`);
|
|
236
|
-
return this.connect(printer.address, printer.name);
|
|
241
|
+
return this.connect(printer.address, printer.name, false);
|
|
237
242
|
}
|
|
238
243
|
async ensureConnected() {
|
|
239
244
|
if (this.isConnected()) {
|
|
@@ -241,10 +246,11 @@ class PrinterService {
|
|
|
241
246
|
}
|
|
242
247
|
const printer = await this.getSelectedPrinter();
|
|
243
248
|
if (!printer) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
249
|
+
notifyDevice({
|
|
250
|
+
name: "printer.missing",
|
|
251
|
+
title: "Sin impresora",
|
|
252
|
+
message: "Selecciona una impresora primero",
|
|
253
|
+
variant: "danger",
|
|
248
254
|
});
|
|
249
255
|
return false;
|
|
250
256
|
}
|
package/dist/tools/utils/date.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dayOf, isDay } from "@sincpro/client-framework";
|
|
1
2
|
import dayjs from "dayjs";
|
|
2
3
|
import timezone from "dayjs/plugin/timezone";
|
|
3
4
|
import utc from "dayjs/plugin/utc";
|
|
@@ -53,7 +54,7 @@ export function formatDate(input, timezone, options) {
|
|
|
53
54
|
const usedLocale = options?.locale ?? deviceLocale;
|
|
54
55
|
try {
|
|
55
56
|
const rawStr = typeof input === "string" ? input : input.toISOString();
|
|
56
|
-
const isDateOnly =
|
|
57
|
+
const isDateOnly = typeof input === "string" && isDay(input);
|
|
57
58
|
// Auto-detect showTime si no se pasa explicitamente
|
|
58
59
|
const effectiveShowTime = options?.showTime !== undefined
|
|
59
60
|
? options.showTime
|
|
@@ -100,11 +101,11 @@ export function formatDateWithDefaultTimezone(input, options) {
|
|
|
100
101
|
export function getCurrentDateInTimezone(timezone) {
|
|
101
102
|
const effectiveTimezone = timezone || DEFAULT_TIMEZONE;
|
|
102
103
|
try {
|
|
103
|
-
return
|
|
104
|
+
return dayOf(new Date().toISOString(), effectiveTimezone) ?? dayjs().format("YYYY-MM-DD");
|
|
104
105
|
}
|
|
105
106
|
catch (error) {
|
|
106
107
|
console.warn("Error obteniendo fecha actual en timezone:", error);
|
|
107
|
-
return dayjs().format("YYYY-MM-DD");
|
|
108
|
+
return dayjs().format("YYYY-MM-DD");
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
/**
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function
|
|
1
|
+
import { Decimal, type DecimalLike } from "@sincpro/client-framework";
|
|
2
|
+
export declare function toDecimal(input?: DecimalLike | null): Decimal;
|
|
3
|
+
export declare function parseToMonetaryNumber(input?: DecimalLike | null): Decimal;
|
|
4
|
+
export declare function formatTwoDecimals(value?: DecimalLike | null): string;
|
|
5
|
+
export declare function discountOf(total: DecimalLike, discount: DecimalLike): Decimal;
|
|
6
|
+
export declare function calculateDiscountedTotal(total: DecimalLike, discount: DecimalLike): Decimal;
|
|
@@ -1,31 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export function
|
|
1
|
+
import { Decimal } from "@sincpro/client-framework";
|
|
2
|
+
export function toDecimal(input) {
|
|
3
3
|
if (input == null)
|
|
4
|
-
return 0;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
return new Decimal(0);
|
|
5
|
+
if (typeof input === "number" && !Number.isFinite(input))
|
|
6
|
+
return new Decimal(0);
|
|
7
|
+
if (typeof input === "string") {
|
|
8
|
+
const text = input.trim();
|
|
9
|
+
if (!/[0-9]/.test(text))
|
|
10
|
+
return new Decimal(0);
|
|
11
|
+
try {
|
|
12
|
+
return new Decimal(text.replace(/[^0-9.-]+/g, ""));
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return new Decimal(0);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
9
18
|
try {
|
|
10
|
-
return
|
|
19
|
+
return new Decimal(input);
|
|
11
20
|
}
|
|
12
21
|
catch {
|
|
13
|
-
return 0;
|
|
22
|
+
return new Decimal(0);
|
|
14
23
|
}
|
|
15
24
|
}
|
|
25
|
+
export function parseToMonetaryNumber(input) {
|
|
26
|
+
return toDecimal(input);
|
|
27
|
+
}
|
|
16
28
|
export function formatTwoDecimals(value) {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
const text = toDecimal(value).rounded(2).toString();
|
|
30
|
+
const negative = text.startsWith("-");
|
|
31
|
+
const [whole, fraction = "00"] = (negative ? text.slice(1) : text).split(".");
|
|
32
|
+
const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
33
|
+
return `${negative ? "-" : ""}${grouped},${fraction}`;
|
|
34
|
+
}
|
|
35
|
+
export function discountOf(total, discount) {
|
|
36
|
+
const rate = toDecimal(discount);
|
|
37
|
+
if (rate.isZero)
|
|
38
|
+
return new Decimal(0);
|
|
39
|
+
return toDecimal(total).times(rate).dividedBy(100, 8);
|
|
24
40
|
}
|
|
25
41
|
export function calculateDiscountedTotal(total, discount) {
|
|
26
|
-
|
|
27
|
-
return 0;
|
|
28
|
-
}
|
|
29
|
-
const result = (parseToMonetaryNumber(total) * discount) / 100;
|
|
30
|
-
return parseToMonetaryNumber(result);
|
|
42
|
+
return discountOf(total, discount);
|
|
31
43
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function safeJsonStringify(obj:
|
|
1
|
+
export declare function safeJsonStringify(obj: unknown, pretty?: boolean): string;
|
|
2
2
|
export declare function safeJsonParse(json: string): any;
|
|
@@ -1,44 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (
|
|
4
|
-
return
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return Array.from(value);
|
|
13
|
-
}
|
|
14
|
-
if (typeof value === "object" && value !== null) {
|
|
15
|
-
if (seen.has(value)) {
|
|
16
|
-
return "[Circular]";
|
|
17
|
-
}
|
|
18
|
-
seen.add(value);
|
|
19
|
-
}
|
|
20
|
-
return value;
|
|
21
|
-
}, 2);
|
|
1
|
+
import { readValues, valuesOf } from "@sincpro/client-framework";
|
|
2
|
+
function publishable(value, seen) {
|
|
3
|
+
if (value === null || typeof value !== "object")
|
|
4
|
+
return value;
|
|
5
|
+
if (seen.has(value))
|
|
6
|
+
return "[Circular]";
|
|
7
|
+
if (value instanceof Uint8Array ||
|
|
8
|
+
value instanceof ArrayBuffer ||
|
|
9
|
+
value instanceof DataView ||
|
|
10
|
+
typeof value.toJSON === "function") {
|
|
11
|
+
return value;
|
|
22
12
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
13
|
+
seen.add(value);
|
|
14
|
+
try {
|
|
27
15
|
if (value instanceof Map) {
|
|
28
|
-
return
|
|
16
|
+
return new Map([...value].map(([key, item]) => [key, publishable(item, seen)]));
|
|
29
17
|
}
|
|
30
18
|
if (value instanceof Set) {
|
|
31
|
-
return
|
|
19
|
+
return new Set([...value].map((item) => publishable(item, seen)));
|
|
32
20
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
21
|
+
if (Array.isArray(value))
|
|
22
|
+
return value.map((item) => publishable(item, seen));
|
|
23
|
+
const published = {};
|
|
24
|
+
for (const [key, item] of Object.entries(value)) {
|
|
25
|
+
if (key.startsWith("_") || typeof item === "function")
|
|
26
|
+
continue;
|
|
27
|
+
published[key] = publishable(item, seen);
|
|
38
28
|
}
|
|
39
|
-
return
|
|
40
|
-
}
|
|
29
|
+
return published;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
seen.delete(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function safeJsonStringify(obj, pretty = false) {
|
|
36
|
+
const wire = valuesOf(publishable(obj, new WeakSet()));
|
|
37
|
+
return JSON.stringify(wire, null, pretty ? 2 : undefined);
|
|
41
38
|
}
|
|
42
39
|
export function safeJsonParse(json) {
|
|
43
|
-
return
|
|
40
|
+
return readValues(json);
|
|
44
41
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function DeviceNotices(): null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { textOf } from "../../domain/events/label";
|
|
2
|
+
import { useCommon } from "../../entrypoints/ui/common_provider";
|
|
3
|
+
import { useToast } from "@sincpro/mobile-ui/Feedback";
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { useActivity } from "./useActivity";
|
|
6
|
+
const VARIANT = {
|
|
7
|
+
success: "success",
|
|
8
|
+
danger: "danger",
|
|
9
|
+
info: "info",
|
|
10
|
+
};
|
|
11
|
+
export function DeviceNotices() {
|
|
12
|
+
const { notices } = useActivity();
|
|
13
|
+
const { locale } = useCommon();
|
|
14
|
+
const toast = useToast();
|
|
15
|
+
const shownRef = useRef(new Set());
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
for (const notice of notices) {
|
|
18
|
+
if (shownRef.current.has(notice.id))
|
|
19
|
+
continue;
|
|
20
|
+
shownRef.current.add(notice.id);
|
|
21
|
+
toast.show({
|
|
22
|
+
title: textOf(notice.label, locale),
|
|
23
|
+
message: textOf(notice.detail ?? notice.label, locale),
|
|
24
|
+
variant: VARIANT[notice.variant ?? "info"],
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}, [locale, notices, toast]);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { textOf } from "../../domain/events/label";
|
|
2
|
+
import { useCommon } from "../../entrypoints/ui/common_provider";
|
|
3
|
+
import { useToast } from "@sincpro/mobile-ui/Feedback";
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { useActivity } from "./useActivity";
|
|
6
|
+
const MAX_ERROR_LEN = 150;
|
|
7
|
+
const MIN_VISIBLE_MS = 1200;
|
|
8
|
+
function ProcessToast() {
|
|
9
|
+
const { queue, crons, failure } = useActivity();
|
|
10
|
+
const { locale } = useCommon();
|
|
11
|
+
const toast = useToast();
|
|
12
|
+
const loadingIdRef = useRef(null);
|
|
13
|
+
const shownErrorRef = useRef(null);
|
|
14
|
+
const startedAtRef = useRef(null);
|
|
15
|
+
const hideTimerRef = useRef(null);
|
|
16
|
+
const progress = queue ?? crons[0];
|
|
17
|
+
const progressLabel = textOf(progress?.label, locale);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (hideTimerRef.current) {
|
|
20
|
+
clearTimeout(hideTimerRef.current);
|
|
21
|
+
hideTimerRef.current = null;
|
|
22
|
+
}
|
|
23
|
+
const hideLoading = () => {
|
|
24
|
+
if (!loadingIdRef.current)
|
|
25
|
+
return;
|
|
26
|
+
toast.hide(loadingIdRef.current);
|
|
27
|
+
loadingIdRef.current = null;
|
|
28
|
+
startedAtRef.current = null;
|
|
29
|
+
};
|
|
30
|
+
if (progress && !failure) {
|
|
31
|
+
if (startedAtRef.current == null)
|
|
32
|
+
startedAtRef.current = Date.now();
|
|
33
|
+
if (loadingIdRef.current) {
|
|
34
|
+
toast.update(loadingIdRef.current, { message: progressLabel, variant: "loading" });
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
loadingIdRef.current = toast.loading(progressLabel);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (loadingIdRef.current) {
|
|
41
|
+
const elapsed = startedAtRef.current
|
|
42
|
+
? Date.now() - startedAtRef.current
|
|
43
|
+
: MIN_VISIBLE_MS;
|
|
44
|
+
const wait = failure ? 0 : Math.max(0, MIN_VISIBLE_MS - elapsed);
|
|
45
|
+
hideTimerRef.current = setTimeout(hideLoading, wait);
|
|
46
|
+
}
|
|
47
|
+
return () => {
|
|
48
|
+
if (hideTimerRef.current)
|
|
49
|
+
clearTimeout(hideTimerRef.current);
|
|
50
|
+
};
|
|
51
|
+
}, [failure, progress, progressLabel, toast]);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (!failure) {
|
|
54
|
+
shownErrorRef.current = null;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (shownErrorRef.current === failure.id)
|
|
58
|
+
return;
|
|
59
|
+
shownErrorRef.current = failure.id;
|
|
60
|
+
const raw = failure.detail != null ? textOf(failure.detail, locale) : undefined;
|
|
61
|
+
const detail = raw
|
|
62
|
+
? raw.length > MAX_ERROR_LEN
|
|
63
|
+
? `${raw.slice(0, MAX_ERROR_LEN)}...`
|
|
64
|
+
: raw
|
|
65
|
+
: undefined;
|
|
66
|
+
const title = textOf(failure.label, locale);
|
|
67
|
+
toast.danger(detail ?? title, { title: `Error: ${title}` });
|
|
68
|
+
}, [failure, locale, toast]);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
export default ProcessToast;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ACTIVITY_EVENT, ACTIVITY_SETTING_EVENT, activityVisible, applyActivity, emptyActivity, loadActivityEnabled, } from "../../infrastructure/ui/activity";
|
|
2
|
+
import { UIEventBus } from "../../infrastructure/ui/UIEventBus";
|
|
3
|
+
import { useEffect, useMemo, useState } from "react";
|
|
4
|
+
const CHANNELS_ON = {
|
|
5
|
+
queue: true,
|
|
6
|
+
cron: true,
|
|
7
|
+
device: true,
|
|
8
|
+
};
|
|
9
|
+
export function useActivity(options) {
|
|
10
|
+
const all = options?.all ?? false;
|
|
11
|
+
const [state, setState] = useState(emptyActivity);
|
|
12
|
+
const [enabled, setEnabled] = useState(CHANNELS_ON);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
let alive = true;
|
|
15
|
+
loadActivityEnabled().then((next) => {
|
|
16
|
+
if (alive)
|
|
17
|
+
setEnabled(next);
|
|
18
|
+
});
|
|
19
|
+
return () => {
|
|
20
|
+
alive = false;
|
|
21
|
+
};
|
|
22
|
+
}, []);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const offFact = UIEventBus.on(ACTIVITY_EVENT, (payload) => {
|
|
25
|
+
setState((current) => applyActivity(current, payload));
|
|
26
|
+
}, { debounce: false });
|
|
27
|
+
const offSetting = UIEventBus.on(ACTIVITY_SETTING_EVENT, (payload) => {
|
|
28
|
+
const change = payload;
|
|
29
|
+
setEnabled((current) => ({ ...current, [change.channel]: change.enabled }));
|
|
30
|
+
}, { debounce: false });
|
|
31
|
+
return () => {
|
|
32
|
+
offFact();
|
|
33
|
+
offSetting();
|
|
34
|
+
};
|
|
35
|
+
}, []);
|
|
36
|
+
return useMemo(() => {
|
|
37
|
+
const visible = state.running.filter((fact) => activityVisible(fact, enabled, all));
|
|
38
|
+
const queues = visible.filter((fact) => fact.channel === "queue");
|
|
39
|
+
return {
|
|
40
|
+
queue: queues[queues.length - 1],
|
|
41
|
+
crons: visible.filter((fact) => fact.channel === "cron"),
|
|
42
|
+
failure: state.failure && activityVisible(state.failure, enabled, all)
|
|
43
|
+
? state.failure
|
|
44
|
+
: undefined,
|
|
45
|
+
notices: state.notices.filter((fact) => activityVisible(fact, enabled, all)),
|
|
46
|
+
};
|
|
47
|
+
}, [all, enabled, state]);
|
|
48
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare function DebugBanner(): import("react
|
|
1
|
+
declare function DebugBanner(): import("react").JSX.Element | null;
|
|
2
2
|
export { DebugBanner };
|
|
@@ -4,5 +4,5 @@ interface BluetoothDeviceSelectorModalProps {
|
|
|
4
4
|
onClose: () => void;
|
|
5
5
|
onSelect: (device: BluetoothDevice) => void;
|
|
6
6
|
}
|
|
7
|
-
declare function BluetoothDeviceSelectorModal({ visible, onClose, onSelect, }: BluetoothDeviceSelectorModalProps): import("react
|
|
7
|
+
declare function BluetoothDeviceSelectorModal({ visible, onClose, onSelect, }: BluetoothDeviceSelectorModalProps): import("react").JSX.Element;
|
|
8
8
|
export { BluetoothDeviceSelectorModal };
|
|
@@ -23,6 +23,13 @@ function BluetoothDeviceSelectorModal({ visible, onClose, onSelect, }) {
|
|
|
23
23
|
const [loading, setLoading] = useState(false);
|
|
24
24
|
const [selectedDevice, setSelectedDevice] = useState(null);
|
|
25
25
|
const [connecting, setConnecting] = useState(false);
|
|
26
|
+
const [prevVisible, setPrevVisible] = useState(visible);
|
|
27
|
+
if (visible !== prevVisible) {
|
|
28
|
+
setPrevVisible(visible);
|
|
29
|
+
if (visible) {
|
|
30
|
+
setSelectedDevice(null);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
26
33
|
const loadDevices = useCallback(async () => {
|
|
27
34
|
setLoading(true);
|
|
28
35
|
try {
|
|
@@ -38,8 +45,7 @@ function BluetoothDeviceSelectorModal({ visible, onClose, onSelect, }) {
|
|
|
38
45
|
}, []);
|
|
39
46
|
useEffect(() => {
|
|
40
47
|
if (visible) {
|
|
41
|
-
loadDevices();
|
|
42
|
-
setSelectedDevice(null);
|
|
48
|
+
Promise.resolve().then(() => loadDevices());
|
|
43
49
|
}
|
|
44
50
|
}, [visible, loadDevices]);
|
|
45
51
|
async function handleConfirm() {
|
|
@@ -4,5 +4,5 @@ interface DeadLetterErrorBlockProps {
|
|
|
4
4
|
onToggle: () => void;
|
|
5
5
|
previewChars?: number;
|
|
6
6
|
}
|
|
7
|
-
declare function DeadLetterErrorBlock({ errorMessage, expanded, onToggle, previewChars, }: DeadLetterErrorBlockProps): import("react
|
|
7
|
+
declare function DeadLetterErrorBlock({ errorMessage, expanded, onToggle, previewChars, }: DeadLetterErrorBlockProps): import("react").JSX.Element | null;
|
|
8
8
|
export default DeadLetterErrorBlock;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IntegrationEvent } from "../../../domain/events";
|
|
2
2
|
interface EventTimelineItemProps {
|
|
3
|
-
event:
|
|
3
|
+
event: IntegrationEvent;
|
|
4
4
|
isLast?: boolean;
|
|
5
5
|
}
|
|
6
|
-
declare function EventTimelineItem({ event, isLast }: EventTimelineItemProps): import("react
|
|
6
|
+
declare function EventTimelineItem({ event, isLast }: EventTimelineItemProps): import("react").JSX.Element;
|
|
7
7
|
export default EventTimelineItem;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import { EEventStatus } from "../../../domain/
|
|
2
|
+
import { EEventStatus } from "../../../domain/events";
|
|
3
3
|
import { Display } from "@sincpro/mobile-ui/Display";
|
|
4
4
|
import CopyableText from "@sincpro/mobile-ui/Display/Display.CopyableText";
|
|
5
5
|
import { useTheme } from "@sincpro/mobile-ui/theme";
|
|
@@ -4,5 +4,5 @@ interface GeoPermissionCardProps {
|
|
|
4
4
|
loading?: boolean;
|
|
5
5
|
handleRequestPermission?: () => void;
|
|
6
6
|
}
|
|
7
|
-
declare function GeoPermissionCard({ title, loading, handleRequestPermission, hasPermission, }: GeoPermissionCardProps): import("react
|
|
7
|
+
declare function GeoPermissionCard({ title, loading, handleRequestPermission, hasPermission, }: GeoPermissionCardProps): import("react").JSX.Element;
|
|
8
8
|
export default GeoPermissionCard;
|
|
@@ -3,5 +3,5 @@ interface TimeZoneSelectorProps {
|
|
|
3
3
|
onSelect?: (tz: TimezoneLocale) => void;
|
|
4
4
|
timezone?: string | null;
|
|
5
5
|
}
|
|
6
|
-
export declare function TimeZoneSelector({ onSelect, timezone }: TimeZoneSelectorProps): import("react
|
|
6
|
+
export declare function TimeZoneSelector({ onSelect, timezone }: TimeZoneSelectorProps): import("react").JSX.Element;
|
|
7
7
|
export {};
|
|
@@ -5,5 +5,5 @@ interface TimeZoneSelectorModalProps {
|
|
|
5
5
|
onSelect: (tz: TimezoneLocale) => void;
|
|
6
6
|
currentTimezone?: string | null;
|
|
7
7
|
}
|
|
8
|
-
declare function TimeZoneSelectorModal({ visible, onClose, onSelect, currentTimezone, }: TimeZoneSelectorModalProps): import("react
|
|
8
|
+
declare function TimeZoneSelectorModal({ visible, onClose, onSelect, currentTimezone, }: TimeZoneSelectorModalProps): import("react").JSX.Element;
|
|
9
9
|
export { TimeZoneSelectorModal };
|