@controleonline/ui-common 1.2.70
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/.github/agents/developer.agent.md +30 -0
- package/.github/agents/devops.agent.md +30 -0
- package/.github/agents/qa.agent.md +30 -0
- package/.github/agents/security.agent.md +30 -0
- package/.github/workflows/npmjs.yml +35 -0
- package/.github/workflows/pull-request-checks.yml +19 -0
- package/.scrutinizer.yml +24 -0
- package/FUNDING.yml +1 -0
- package/package.json +28 -0
- package/src/api/fetch.js +74 -0
- package/src/api/index.js +155 -0
- package/src/api/localDB.js +131 -0
- package/src/api/queue.js +66 -0
- package/src/react/assets/tap.mp3 +0 -0
- package/src/react/components/AddImportModal.js +157 -0
- package/src/react/components/AddImportModal.styles.js +81 -0
- package/src/react/components/BackgroundRuntimeBridge.js +219 -0
- package/src/react/components/BottomNavigationBar.config.js +238 -0
- package/src/react/components/BottomNavigationBar.js +120 -0
- package/src/react/components/BottomNavigationBar.styles.js +110 -0
- package/src/react/components/CategoryForm.js +572 -0
- package/src/react/components/CategoryForm.styles.js +334 -0
- package/src/react/components/ConfirmModal.js +24 -0
- package/src/react/components/ConfirmModal.styles.js +43 -0
- package/src/react/components/ContextHelpButton.js +69 -0
- package/src/react/components/ContextHelpButton.styles.js +62 -0
- package/src/react/components/DefaultProvider.native.js +848 -0
- package/src/react/components/DefaultProvider.styles.js +21 -0
- package/src/react/components/DefaultProvider.web.js +909 -0
- package/src/react/components/DeliveryPushBridge.native.js +314 -0
- package/src/react/components/DeliveryPushBridge.web.js +5 -0
- package/src/react/components/DeviceAlertSoundService.js +499 -0
- package/src/react/components/EntityLogContent.js +909 -0
- package/src/react/components/EntityLogContent.styles.js +400 -0
- package/src/react/components/EventBus.js +12 -0
- package/src/react/components/KioskModeBridge.js +65 -0
- package/src/react/components/LauncherModeBridge.js +47 -0
- package/src/react/components/LinkedOrderProductsTab.js +388 -0
- package/src/react/components/LinkedOrderProductsTab.styles.js +180 -0
- package/src/react/components/ManagerPushBridge.native.js +345 -0
- package/src/react/components/MessageService.js +314 -0
- package/src/react/components/Paywall/Google.js +89 -0
- package/src/react/components/PrintService.js +778 -0
- package/src/react/components/ProductCatalogCacheService.js +45 -0
- package/src/react/components/RemoteCheckoutService.js +292 -0
- package/src/react/components/RuntimeBottomNavigationBar.js +151 -0
- package/src/react/components/RuntimeInfoFooter.js +214 -0
- package/src/react/components/RuntimeInfoFooter.styles.js +56 -0
- package/src/react/components/SystemErrorToast.js +29 -0
- package/src/react/components/SystemErrorToast.styles.js +38 -0
- package/src/react/components/TouchFeedbackProvider.js +65 -0
- package/src/react/components/UnifiedPaymentBar.js +155 -0
- package/src/react/components/UnifiedPaymentBar.styles.js +174 -0
- package/src/react/components/WebsocketListener.native.js +487 -0
- package/src/react/components/WebsocketListener.web.js +102 -0
- package/src/react/components/inputs/IdInput.js +49 -0
- package/src/react/components/inputs/IdInput.styles.js +26 -0
- package/src/react/components/inputs/InvoiceDueDateFilterInput.js +74 -0
- package/src/react/components/inputs/InvoiceDueDateFilterInput.styles.js +34 -0
- package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.js +115 -0
- package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.styles.js +39 -0
- package/src/react/components/lists/CategoriesList.js +56 -0
- package/src/react/components/lists/PaymentTypeList.js +55 -0
- package/src/react/components/lists/ReceiverList.js +56 -0
- package/src/react/components/lists/SelectList.styles.js +18 -0
- package/src/react/components/lists/StatusList.js +55 -0
- package/src/react/components/lists/WalletList.js +54 -0
- package/src/react/components/radio/Spotify.js +144 -0
- package/src/react/components/radio/Spotify.styles.js +32 -0
- package/src/react/components/radio/YouTube.js +82 -0
- package/src/react/components/radio/YouTube.styles.js +16 -0
- package/src/react/components/toastConfig.js +16 -0
- package/src/react/config/deviceConfigBootstrap.js +571 -0
- package/src/react/index.js +4 -0
- package/src/react/localStorage.js +30 -0
- package/src/react/pages/EntityLogPage.js +124 -0
- package/src/react/pages/EntityLogPage.styles.js +17 -0
- package/src/react/pages/GenericLogPage.js +760 -0
- package/src/react/pages/GenericLogPage.styles.js +401 -0
- package/src/react/pages/Imports.js +361 -0
- package/src/react/pages/Imports.styles.js +223 -0
- package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +462 -0
- package/src/react/pages/SettingsPage/index.js +1171 -0
- package/src/react/pages/SettingsPage/index.styles.js +122 -0
- package/src/react/print/jobs.js +147 -0
- package/src/react/print/providers/local.js +53 -0
- package/src/react/print/providers/remote.js +81 -0
- package/src/react/print/selection.js +296 -0
- package/src/react/print/usePrintButtonController.js +474 -0
- package/src/react/router/routes.js +42 -0
- package/src/react/services/NetworkPrinterService.native.js +391 -0
- package/src/react/services/NetworkPrinterService.web.js +15 -0
- package/src/react/stores/index.js +128 -0
- package/src/react/stores/storeErrorBridge.js +36 -0
- package/src/react/utils/backgroundRuntimeRegistration.js +69 -0
- package/src/react/utils/cashPayment.js +87 -0
- package/src/react/utils/commercialDocumentOrders.js +269 -0
- package/src/react/utils/dateRangeFilter.js +264 -0
- package/src/react/utils/deviceRuntime.js +193 -0
- package/src/react/utils/entityDisplay.js +231 -0
- package/src/react/utils/entityLog.js +649 -0
- package/src/react/utils/fileUrl.js +102 -0
- package/src/react/utils/frontendDebugLog.js +45 -0
- package/src/react/utils/googleMapsConfig.js +49 -0
- package/src/react/utils/importStatus.js +100 -0
- package/src/react/utils/invoiceDueDateMessages.js +14 -0
- package/src/react/utils/invoicePresentation.js +46 -0
- package/src/react/utils/logSettings.js +143 -0
- package/src/react/utils/maintenanceSettings.js +53 -0
- package/src/react/utils/managerOrderNotifications.js +523 -0
- package/src/react/utils/mapNavigation.js +76 -0
- package/src/react/utils/menuCatalogConfig.js +8 -0
- package/src/react/utils/menuCatalogDownload.js +157 -0
- package/src/react/utils/networkCameraDevices.js +175 -0
- package/src/react/utils/networkDeviceProfiles.js +135 -0
- package/src/react/utils/normalizedCatalogDownload.js +157 -0
- package/src/react/utils/notificationNavigation.js +94 -0
- package/src/react/utils/notificationSound.js +42 -0
- package/src/react/utils/paymentDevices.js +397 -0
- package/src/react/utils/paymentGatewayExecution.js +91 -0
- package/src/react/utils/paymentOptions.js +88 -0
- package/src/react/utils/peopleDisplay.js +39 -0
- package/src/react/utils/printerDevices.js +465 -0
- package/src/react/utils/remotePayment.js +61 -0
- package/src/react/utils/runtimeFooter.js +475 -0
- package/src/react/utils/runtimeLanguage.js +50 -0
- package/src/react/utils/runtimeMenu.js +224 -0
- package/src/react/utils/screenMetrics.js +30 -0
- package/src/react/utils/shopConfig.js +294 -0
- package/src/react/utils/shopFranchises.js +114 -0
- package/src/react/utils/socketRuntimePipeline.js +454 -0
- package/src/react/utils/spoolAckTracker.js +77 -0
- package/src/react/utils/storeColumns.js +427 -0
- package/src/react/utils/systemErrorChannel.js +109 -0
- package/src/react/utils/systemErrorMessage.js +67 -0
- package/src/react/utils/toastPresentation.js +53 -0
- package/src/react/utils/websocketSharedRuntime.js +826 -0
- package/src/store/acl/getters.js +4 -0
- package/src/store/acl/index.js +19 -0
- package/src/store/acl/mutation_types.js +4 -0
- package/src/store/acl/mutations.js +17 -0
- package/src/store/address/city.js +22 -0
- package/src/store/categories/category_file/index.js +25 -0
- package/src/store/categories/index.js +93 -0
- package/src/store/configs/customActions.js +131 -0
- package/src/store/configs/index.js +25 -0
- package/src/store/connections/customActions.js +26 -0
- package/src/store/connections/index.js +124 -0
- package/src/store/device/index.js +22 -0
- package/src/store/device_config/customActions.js +190 -0
- package/src/store/device_config/index.js +28 -0
- package/src/store/entity_log/customActions.js +63 -0
- package/src/store/entity_log/index.js +25 -0
- package/src/store/extra/data.js +85 -0
- package/src/store/extra/fields.js +88 -0
- package/src/store/file/actions.js +27 -0
- package/src/store/file/index.js +24 -0
- package/src/store/imports/index.js +88 -0
- package/src/store/print/customActions.js +251 -0
- package/src/store/print/index.js +28 -0
- package/src/store/printer/customActions.js +54 -0
- package/src/store/printer/index.js +26 -0
- package/src/store/runtime_debug/customActions.js +71 -0
- package/src/store/runtime_debug/index.js +30 -0
- package/src/store/status/index.js +65 -0
- package/src/store/timezones/index.js +43 -0
- package/src/store/websocket/customActions.js +24 -0
- package/src/store/websocket/index.js +28 -0
- package/src/tests/react/components/LauncherModeBridge.test.js +93 -0
- package/src/tests/react/config/deviceConfigBootstrap.test.js +337 -0
- package/src/tests/react/print/localPrintProvider.test.js +45 -0
- package/src/tests/react/utils/backgroundRuntimeRegistration.test.js +123 -0
- package/src/tests/react/utils/cashPayment.test.js +41 -0
- package/src/tests/react/utils/dateRangeFilter.test.mjs +29 -0
- package/src/tests/react/utils/entityDisplay.test.js +18 -0
- package/src/tests/react/utils/googleMapsConfig.test.js +32 -0
- package/src/tests/react/utils/importStatus.test.js +85 -0
- package/src/tests/react/utils/invoicePresentation.test.mjs +40 -0
- package/src/tests/react/utils/managerOrderNotifications.test.js +127 -0
- package/src/tests/react/utils/mapNavigation.test.js +58 -0
- package/src/tests/react/utils/notificationNavigation.test.js +39 -0
- package/src/tests/react/utils/notificationSound.test.js +27 -0
- package/src/tests/react/utils/paymentDevices.test.js +88 -0
- package/src/tests/react/utils/runtimeFooter.test.js +429 -0
- package/src/tests/react/utils/runtimeLanguage.test.js +80 -0
- package/src/tests/react/utils/runtimeMenu.test.js +174 -0
- package/src/tests/react/utils/shopFranchises.test.js +82 -0
- package/src/tests/react/utils/socketRuntimePipeline.test.js +124 -0
- package/src/tests/react/utils/spoolAckTracker.test.js +40 -0
- package/src/tests/react/utils/storeErrorBridge.test.js +66 -0
- package/src/tests/react/utils/systemErrorChannel.test.js +58 -0
- package/src/tests/react/utils/systemErrorMessage.test.js +59 -0
- package/src/tests/react/utils/toastPresentation.test.js +75 -0
- package/src/tests/react/utils/translate.test.mjs +396 -0
- package/src/tests/react/utils/websocketSharedRuntime.test.js +245 -0
- package/src/utils/apiEntryPoint.js +31 -0
- package/src/utils/appDomain.js +50 -0
- package/src/utils/config.js +14 -0
- package/src/utils/formatter.js +419 -0
- package/src/utils/integrationConfigs.js +79 -0
- package/src/utils/methods.js +23 -0
- package/src/utils/oauth.js +42 -0
- package/src/utils/translate.js +620 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, {useEffect} from 'react';
|
|
2
|
+
import {useStore} from '@store';
|
|
3
|
+
|
|
4
|
+
const ProductCatalogCacheService = () => {
|
|
5
|
+
const categoriesStore = useStore('categories');
|
|
6
|
+
const productsStore = useStore('products');
|
|
7
|
+
|
|
8
|
+
const categoryActions = categoriesStore.actions;
|
|
9
|
+
const productActions = productsStore.actions;
|
|
10
|
+
|
|
11
|
+
const {messages, message} = categoriesStore.getters;
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (
|
|
15
|
+
messages &&
|
|
16
|
+
messages.length > 0 &&
|
|
17
|
+
(!message || Object.keys(message).length === 0)
|
|
18
|
+
) {
|
|
19
|
+
const nextMessages = [...messages];
|
|
20
|
+
categoryActions.setMessage(nextMessages.pop());
|
|
21
|
+
categoryActions.setMessages(nextMessages);
|
|
22
|
+
}
|
|
23
|
+
}, [categoryActions, message, messages]);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!message || Object.keys(message).length === 0) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (message?.command !== 'clear-product-cache') {
|
|
31
|
+
categoryActions.setMessage(null);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
localStorage.setItem('categories', JSON.stringify([]));
|
|
36
|
+
localStorage.removeItem('categories-company');
|
|
37
|
+
categoryActions.setItems([]);
|
|
38
|
+
productActions.setItems([]);
|
|
39
|
+
categoryActions.setMessage(null);
|
|
40
|
+
}, [categoryActions, message, productActions]);
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default ProductCatalogCacheService;
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import React, {useEffect, useCallback, useRef} from 'react';
|
|
2
|
+
|
|
3
|
+
import {api} from '@controleonline/ui-common/src/api';
|
|
4
|
+
import Formatter from '@controleonline/ui-common/src/utils/formatter';
|
|
5
|
+
import {
|
|
6
|
+
createInvoiceForGatewayFreePayment,
|
|
7
|
+
isGatewayFreePayment,
|
|
8
|
+
} from '@controleonline/ui-common/src/react/utils/cashPayment';
|
|
9
|
+
import {
|
|
10
|
+
normalizeGatewayPaymentError,
|
|
11
|
+
runConfiguredGatewayPayment,
|
|
12
|
+
} from '@controleonline/ui-common/src/react/utils/paymentGatewayExecution';
|
|
13
|
+
import {
|
|
14
|
+
buildRemotePaymentResultMessage,
|
|
15
|
+
isRemotePaymentRequestMessage,
|
|
16
|
+
normalizeRemotePaymentRequestKey,
|
|
17
|
+
} from '@controleonline/ui-common/src/react/utils/remotePayment';
|
|
18
|
+
|
|
19
|
+
import {useStore} from '@store';
|
|
20
|
+
|
|
21
|
+
const normalizeStatusKey = value => String(value || '').trim().toLowerCase();
|
|
22
|
+
|
|
23
|
+
const extractCollectionItems = response => {
|
|
24
|
+
if (Array.isArray(response)) return response;
|
|
25
|
+
if (Array.isArray(response?.member)) return response.member;
|
|
26
|
+
if (Array.isArray(response?.['hydra:member'])) return response['hydra:member'];
|
|
27
|
+
return [];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const buildStatusIriFromId = value => {
|
|
31
|
+
const normalizedId = String(value || '').replace(/\D/g, '');
|
|
32
|
+
return normalizedId ? `/statuses/${normalizedId}` : null;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
let posPaidInvoiceStatusIriCache = null;
|
|
36
|
+
|
|
37
|
+
const resolvePosPaidInvoiceStatusIri = async fallbackStatusId => {
|
|
38
|
+
if (posPaidInvoiceStatusIriCache) return posPaidInvoiceStatusIriCache;
|
|
39
|
+
|
|
40
|
+
const fallbackIri = buildStatusIriFromId(fallbackStatusId);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const response = await api.fetch('statuses', {
|
|
44
|
+
params: {
|
|
45
|
+
context: 'invoice',
|
|
46
|
+
realStatus: 'closed',
|
|
47
|
+
status: 'paid',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
const items = extractCollectionItems(response);
|
|
51
|
+
const matchedStatus =
|
|
52
|
+
items.find(
|
|
53
|
+
item =>
|
|
54
|
+
normalizeStatusKey(item?.realStatus) === 'closed' &&
|
|
55
|
+
normalizeStatusKey(item?.status) === 'paid',
|
|
56
|
+
) || items[0];
|
|
57
|
+
const resolvedIri =
|
|
58
|
+
matchedStatus?.['@id'] || buildStatusIriFromId(matchedStatus?.id) || fallbackIri;
|
|
59
|
+
|
|
60
|
+
if (resolvedIri) {
|
|
61
|
+
posPaidInvoiceStatusIriCache = resolvedIri;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return resolvedIri;
|
|
65
|
+
} catch {
|
|
66
|
+
return fallbackIri;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const buildOrderIri = value => {
|
|
71
|
+
const normalizedId = String(value || '').replace(/\D/g, '');
|
|
72
|
+
return normalizedId ? `/orders/${normalizedId}` : null;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const Checkout = () => {
|
|
76
|
+
const deviceConfigStore = useStore('device_config');
|
|
77
|
+
const deviceConfigGetters = deviceConfigStore.getters;
|
|
78
|
+
const categoriesStore = useStore('categories');
|
|
79
|
+
const categoryActions = categoriesStore.actions;
|
|
80
|
+
const {item: device} = deviceConfigGetters;
|
|
81
|
+
const ordersStore = useStore('orders');
|
|
82
|
+
const ordersActions = ordersStore.actions;
|
|
83
|
+
const orderProductsStore = useStore('order_products');
|
|
84
|
+
const orderProductsActions = orderProductsStore.actions;
|
|
85
|
+
const invoiceStore = useStore('invoice');
|
|
86
|
+
const invoiceGetters = invoiceStore.getters;
|
|
87
|
+
const invoiceActions = invoiceStore.actions;
|
|
88
|
+
const peopleStore = useStore('people');
|
|
89
|
+
const peopleGetters = peopleStore.getters;
|
|
90
|
+
const {currentCompany, defaultCompany} = peopleGetters;
|
|
91
|
+
const websocketStore = useStore('websocket');
|
|
92
|
+
const websocketActions = websocketStore.actions;
|
|
93
|
+
const {messages, message} = invoiceGetters;
|
|
94
|
+
const processingMessageKeyRef = useRef('');
|
|
95
|
+
|
|
96
|
+
const clear = useCallback(() => {
|
|
97
|
+
localStorage.removeItem('master-device');
|
|
98
|
+
invoiceActions.setError('');
|
|
99
|
+
invoiceActions.setMessage(null);
|
|
100
|
+
invoiceActions.setMessages([]);
|
|
101
|
+
categoryActions.setItems(null);
|
|
102
|
+
ordersActions.setItem(null);
|
|
103
|
+
orderProductsActions.setItems([]);
|
|
104
|
+
invoiceActions.setItems([]);
|
|
105
|
+
ordersActions.setPayable(0);
|
|
106
|
+
}, [categoryActions, invoiceActions, orderProductsActions, ordersActions]);
|
|
107
|
+
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (
|
|
110
|
+
messages &&
|
|
111
|
+
messages.length > 0 &&
|
|
112
|
+
(!message || Object.keys(message).length === 0)
|
|
113
|
+
) {
|
|
114
|
+
const m = [...messages];
|
|
115
|
+
invoiceActions.setMessage(m.pop());
|
|
116
|
+
invoiceActions.setMessages(m);
|
|
117
|
+
}
|
|
118
|
+
}, [messages, message]);
|
|
119
|
+
|
|
120
|
+
const createInvoice = useCallback(async (selectedPayment, total, orderItem) => {
|
|
121
|
+
const paidStatusIri = await resolvePosPaidInvoiceStatusIri(
|
|
122
|
+
defaultCompany?.configs['pos-paid-status'],
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
if (!paidStatusIri) {
|
|
126
|
+
invoiceActions.setError(
|
|
127
|
+
'Nao foi possivel resolver o status pago da invoice do PDV.',
|
|
128
|
+
);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const payload = {
|
|
133
|
+
dueDate: Formatter.getCurrentDate(),
|
|
134
|
+
status: paidStatusIri,
|
|
135
|
+
destinationWallet: selectedPayment.wallet['@id'],
|
|
136
|
+
paymentType: selectedPayment.paymentType['@id'],
|
|
137
|
+
price: total,
|
|
138
|
+
receiver: '/people/' + currentCompany.id,
|
|
139
|
+
order: orderItem?.['@id'],
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return await invoiceActions.save(payload);
|
|
143
|
+
}, [
|
|
144
|
+
currentCompany?.id,
|
|
145
|
+
defaultCompany?.configs,
|
|
146
|
+
invoiceActions,
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
if (!isRemotePaymentRequestMessage(message)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const messageKey = JSON.stringify({
|
|
155
|
+
action: message?.action,
|
|
156
|
+
masterDevice: message?.['master-device'],
|
|
157
|
+
order: message?.order,
|
|
158
|
+
payment: message?.wallet_payment_type?.paymentType?.['@id'],
|
|
159
|
+
requestKey: normalizeRemotePaymentRequestKey(message?.requestKey),
|
|
160
|
+
total: message?.total,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (processingMessageKeyRef.current === messageKey) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
processingMessageKeyRef.current = messageKey;
|
|
168
|
+
|
|
169
|
+
const processMessage = async () => {
|
|
170
|
+
const payment = message.wallet_payment_type;
|
|
171
|
+
const total = Number(message.total || 0);
|
|
172
|
+
const requestKey = normalizeRemotePaymentRequestKey(message?.requestKey);
|
|
173
|
+
const masterDeviceId = String(message?.['master-device'] || '').trim();
|
|
174
|
+
|
|
175
|
+
const sendRemoteResult = async result => {
|
|
176
|
+
if (!masterDeviceId) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
await websocketActions.send(
|
|
182
|
+
buildRemotePaymentResultMessage({
|
|
183
|
+
destinationDeviceId: masterDeviceId,
|
|
184
|
+
orderId: message?.order,
|
|
185
|
+
payment,
|
|
186
|
+
requestKey,
|
|
187
|
+
targetDeviceId: device?.id || device?.device?.device || '',
|
|
188
|
+
targetDeviceLabel:
|
|
189
|
+
device?.device?.alias ||
|
|
190
|
+
device?.device?.name ||
|
|
191
|
+
device?.device?.device ||
|
|
192
|
+
'',
|
|
193
|
+
targetGateway: device?.configs?.['pos-gateway'] || '',
|
|
194
|
+
total,
|
|
195
|
+
...result,
|
|
196
|
+
}),
|
|
197
|
+
);
|
|
198
|
+
} catch {
|
|
199
|
+
// silencioso: o pagamento ja foi executado neste equipamento
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
localStorage.setItem(
|
|
205
|
+
'master-device',
|
|
206
|
+
JSON.stringify({id: message['master-device']}),
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const loadedOrder = await ordersActions.get(message.order);
|
|
210
|
+
const orderIri = loadedOrder?.['@id'] || buildOrderIri(message.order);
|
|
211
|
+
const loadedOrderProducts = orderIri
|
|
212
|
+
? await orderProductsActions
|
|
213
|
+
.getItems({
|
|
214
|
+
order: orderIri,
|
|
215
|
+
})
|
|
216
|
+
.catch(() => [])
|
|
217
|
+
: [];
|
|
218
|
+
let createdInvoice = null;
|
|
219
|
+
let paidAmount = total;
|
|
220
|
+
|
|
221
|
+
if (isGatewayFreePayment(payment)) {
|
|
222
|
+
await createInvoiceForGatewayFreePayment({
|
|
223
|
+
payment,
|
|
224
|
+
total,
|
|
225
|
+
createInvoice: async (selectedPayment, paidTotal) => {
|
|
226
|
+
createdInvoice = await createInvoice(
|
|
227
|
+
selectedPayment,
|
|
228
|
+
paidTotal,
|
|
229
|
+
loadedOrder,
|
|
230
|
+
);
|
|
231
|
+
return createdInvoice;
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
await sendRemoteResult({
|
|
235
|
+
invoice: createdInvoice,
|
|
236
|
+
paidAmount,
|
|
237
|
+
status: 'success',
|
|
238
|
+
});
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const gatewayResult = await runConfiguredGatewayPayment({
|
|
243
|
+
gateway: device?.configs?.['pos-gateway'],
|
|
244
|
+
installments: payment?.installments,
|
|
245
|
+
order: loadedOrder,
|
|
246
|
+
orderProducts: loadedOrderProducts,
|
|
247
|
+
payment,
|
|
248
|
+
total,
|
|
249
|
+
});
|
|
250
|
+
paidAmount = gatewayResult?.paidAmount || total;
|
|
251
|
+
|
|
252
|
+
createdInvoice = await createInvoice(payment, paidAmount, loadedOrder);
|
|
253
|
+
await sendRemoteResult({
|
|
254
|
+
invoice: createdInvoice,
|
|
255
|
+
paidAmount,
|
|
256
|
+
status: 'success',
|
|
257
|
+
});
|
|
258
|
+
} catch (error) {
|
|
259
|
+
const errorMessage = normalizeGatewayPaymentError(
|
|
260
|
+
error,
|
|
261
|
+
'Nao foi possivel concluir o pagamento remoto.',
|
|
262
|
+
);
|
|
263
|
+
invoiceActions.setError(errorMessage);
|
|
264
|
+
await sendRemoteResult({
|
|
265
|
+
error: errorMessage,
|
|
266
|
+
status: 'error',
|
|
267
|
+
});
|
|
268
|
+
} finally {
|
|
269
|
+
clear();
|
|
270
|
+
processingMessageKeyRef.current = '';
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
processMessage();
|
|
275
|
+
}, [
|
|
276
|
+
clear,
|
|
277
|
+
createInvoice,
|
|
278
|
+
device?.configs,
|
|
279
|
+
device?.device,
|
|
280
|
+
device?.id,
|
|
281
|
+
invoiceActions,
|
|
282
|
+
message,
|
|
283
|
+
orderProductsActions,
|
|
284
|
+
ordersActions,
|
|
285
|
+
websocketActions,
|
|
286
|
+
]);
|
|
287
|
+
|
|
288
|
+
return null;
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export default Checkout;
|
|
292
|
+
// TODO(store-first): quando este arquivo for mexido, mover a leitura para stores, remover api.fetch e evitar repassar dados em objetos quando o store ja resolver isso.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, {useEffect, useMemo, useState} from 'react';
|
|
2
|
+
import {useNavigationState} from '@react-navigation/native';
|
|
3
|
+
import {useStore} from '@store';
|
|
4
|
+
import {api} from '@controleonline/ui-common/src/api';
|
|
5
|
+
import {env as APP_ENV} from '@env';
|
|
6
|
+
import {colors as runtimeColors} from '@controleonline/../../src/styles/colors';
|
|
7
|
+
import {resolveThemePalette} from '@controleonline/../../src/styles/branding';
|
|
8
|
+
import BottomNavigationBar from '@controleonline/ui-common/src/react/components/BottomNavigationBar';
|
|
9
|
+
import {
|
|
10
|
+
getBottomNavigationPreset,
|
|
11
|
+
resolveBottomNavigationRoute,
|
|
12
|
+
} from '@controleonline/ui-common/src/react/components/BottomNavigationBar.config';
|
|
13
|
+
import {
|
|
14
|
+
filterRuntimeMenuModulesByType,
|
|
15
|
+
normalizeAppType,
|
|
16
|
+
normalizeRuntimeMenuResponse,
|
|
17
|
+
resolveRuntimeMenuLabel,
|
|
18
|
+
} from '@controleonline/ui-common/src/react/utils/runtimeMenu';
|
|
19
|
+
|
|
20
|
+
const sortRuntimeMenuItems = (left, right) => {
|
|
21
|
+
const orderDiff = Number(left?.sortOrder || 0) - Number(right?.sortOrder || 0);
|
|
22
|
+
if (orderDiff !== 0) return orderDiff;
|
|
23
|
+
return String(left?.label || '').localeCompare(String(right?.label || ''));
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const RuntimeBottomNavigationBar = ({
|
|
27
|
+
activeRouteName: activeRouteNameProp,
|
|
28
|
+
colors: colorsOverride,
|
|
29
|
+
disabled: disabledOverride,
|
|
30
|
+
itemFilter,
|
|
31
|
+
itemMapper,
|
|
32
|
+
menuType = 'toolbar',
|
|
33
|
+
navigation,
|
|
34
|
+
presetKey,
|
|
35
|
+
routeAliases: routeAliasesProp,
|
|
36
|
+
testID = 'bottom-navigation',
|
|
37
|
+
}) => {
|
|
38
|
+
const state = useNavigationState(current => current);
|
|
39
|
+
const activeRouteName =
|
|
40
|
+
activeRouteNameProp || state?.routes?.[state.index]?.name || 'HomePage';
|
|
41
|
+
|
|
42
|
+
const themeStore = useStore('theme');
|
|
43
|
+
const peopleStore = useStore('people');
|
|
44
|
+
const themeGetters = themeStore?.getters || {};
|
|
45
|
+
const peopleGetters = peopleStore?.getters || {};
|
|
46
|
+
const currentCompany = peopleGetters.currentCompany || {};
|
|
47
|
+
const themeColors = themeGetters.colors || {};
|
|
48
|
+
const [runtimeMenus, setRuntimeMenus] = useState([]);
|
|
49
|
+
const preset = presetKey ? getBottomNavigationPreset(presetKey) : null;
|
|
50
|
+
const routeAliases = routeAliasesProp || preset?.routeAliases || {};
|
|
51
|
+
const appType = normalizeAppType(APP_ENV.APP_TYPE);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!currentCompany?.id || !menuType) {
|
|
55
|
+
setRuntimeMenus([]);
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let cancelled = false;
|
|
60
|
+
setRuntimeMenus([]);
|
|
61
|
+
|
|
62
|
+
api
|
|
63
|
+
.fetch('menus-people', {
|
|
64
|
+
params: {
|
|
65
|
+
myCompany: currentCompany.id,
|
|
66
|
+
appType,
|
|
67
|
+
menuType,
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
.then(result => {
|
|
71
|
+
if (!cancelled) {
|
|
72
|
+
setRuntimeMenus(
|
|
73
|
+
normalizeRuntimeMenuResponse(result, {
|
|
74
|
+
appType,
|
|
75
|
+
allowFallback: false,
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
.catch(() => {
|
|
81
|
+
if (!cancelled) {
|
|
82
|
+
setRuntimeMenus([]);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return () => {
|
|
87
|
+
cancelled = true;
|
|
88
|
+
};
|
|
89
|
+
}, [appType, currentCompany?.id, menuType]);
|
|
90
|
+
|
|
91
|
+
const colors = useMemo(() => {
|
|
92
|
+
if (colorsOverride) {
|
|
93
|
+
return colorsOverride;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return resolveThemePalette(
|
|
97
|
+
{
|
|
98
|
+
...themeColors,
|
|
99
|
+
...(currentCompany?.theme?.colors || {}),
|
|
100
|
+
},
|
|
101
|
+
runtimeColors,
|
|
102
|
+
);
|
|
103
|
+
}, [colorsOverride, currentCompany?.theme?.colors, themeColors]);
|
|
104
|
+
|
|
105
|
+
const navItems = useMemo(() => {
|
|
106
|
+
const mapper = typeof itemMapper === 'function' ? itemMapper : item => item;
|
|
107
|
+
const filter = typeof itemFilter === 'function' ? itemFilter : () => true;
|
|
108
|
+
|
|
109
|
+
return filterRuntimeMenuModulesByType(runtimeMenus, menuType)
|
|
110
|
+
.flatMap(module => (Array.isArray(module?.menus) ? module.menus : []))
|
|
111
|
+
.map(item => mapper({...item}))
|
|
112
|
+
.filter(Boolean)
|
|
113
|
+
.filter(filter)
|
|
114
|
+
.sort(sortRuntimeMenuItems)
|
|
115
|
+
.map(item => ({
|
|
116
|
+
route: item.route,
|
|
117
|
+
icon: item.icon || 'circle',
|
|
118
|
+
label: resolveRuntimeMenuLabel(item, global.t?.t),
|
|
119
|
+
routeParams: item.routeParams,
|
|
120
|
+
menuType: item.menuType,
|
|
121
|
+
}))
|
|
122
|
+
.filter(item => Boolean(item.route));
|
|
123
|
+
}, [itemFilter, itemMapper, menuType, runtimeMenus]);
|
|
124
|
+
|
|
125
|
+
const resolvedActiveRoute = resolveBottomNavigationRoute(
|
|
126
|
+
routeAliases,
|
|
127
|
+
activeRouteName,
|
|
128
|
+
);
|
|
129
|
+
const knownRoute = navItems.some(item => item.route === resolvedActiveRoute);
|
|
130
|
+
const effectiveActiveRoute = knownRoute
|
|
131
|
+
? resolvedActiveRoute
|
|
132
|
+
: navItems[0]?.route || activeRouteName;
|
|
133
|
+
|
|
134
|
+
const isDisabled =
|
|
135
|
+
typeof disabledOverride === 'boolean'
|
|
136
|
+
? disabledOverride
|
|
137
|
+
: !currentCompany || Object.keys(currentCompany).length === 0;
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<BottomNavigationBar
|
|
141
|
+
activeRouteName={effectiveActiveRoute}
|
|
142
|
+
colors={colors}
|
|
143
|
+
disabled={isDisabled}
|
|
144
|
+
items={navItems}
|
|
145
|
+
navigation={navigation}
|
|
146
|
+
testID={testID}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export default RuntimeBottomNavigationBar;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import React, {useEffect, useMemo, useState} from 'react';
|
|
2
|
+
import {ActivityIndicator, Text, View, useWindowDimensions} from 'react-native';
|
|
3
|
+
import {useStore, useStores} from '@store';
|
|
4
|
+
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
|
5
|
+
import {colors as runtimeColors} from '@controleonline/../../src/styles/colors';
|
|
6
|
+
import {
|
|
7
|
+
DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY,
|
|
8
|
+
isTruthyValue,
|
|
9
|
+
parseConfigsObject,
|
|
10
|
+
} from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
|
|
11
|
+
import {
|
|
12
|
+
getRuntimeFooterDebugInfo,
|
|
13
|
+
getRuntimeFooterPrimaryText,
|
|
14
|
+
getRuntimeFooterText,
|
|
15
|
+
} from '@controleonline/ui-common/src/react/utils/runtimeFooter';
|
|
16
|
+
import styles from './RuntimeInfoFooter.styles';
|
|
17
|
+
|
|
18
|
+
const ROTATION_INTERVAL_MS = 6000;
|
|
19
|
+
const COMPACT_BREAKPOINT = 720;
|
|
20
|
+
const MAX_INLINE_TEXT_LENGTH = 84;
|
|
21
|
+
|
|
22
|
+
const RuntimeInfoFooter = ({appVersion, defaultCompany, device, colors}) => {
|
|
23
|
+
const {width} = useWindowDimensions();
|
|
24
|
+
const insets = useSafeAreaInsets();
|
|
25
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
26
|
+
const allStores = useStores(state => state);
|
|
27
|
+
const deviceConfigStore = useStore('device_config');
|
|
28
|
+
const runtimeDebugStore = useStore('runtime_debug');
|
|
29
|
+
const deviceConfigItem = deviceConfigStore?.getters?.item || {};
|
|
30
|
+
const runtimeDebugSummary = runtimeDebugStore?.getters?.summary || {};
|
|
31
|
+
|
|
32
|
+
const footerDebugInfo = useMemo(
|
|
33
|
+
() =>
|
|
34
|
+
getRuntimeFooterDebugInfo({
|
|
35
|
+
device,
|
|
36
|
+
appVersion,
|
|
37
|
+
deviceConfig: deviceConfigItem,
|
|
38
|
+
}),
|
|
39
|
+
[appVersion, device, deviceConfigItem],
|
|
40
|
+
);
|
|
41
|
+
const primaryText = useMemo(
|
|
42
|
+
() =>
|
|
43
|
+
footerDebugInfo.primaryText ||
|
|
44
|
+
getRuntimeFooterPrimaryText({
|
|
45
|
+
device,
|
|
46
|
+
appVersion,
|
|
47
|
+
deviceConfig: deviceConfigItem,
|
|
48
|
+
}),
|
|
49
|
+
[appVersion, device, deviceConfigItem, footerDebugInfo.primaryText],
|
|
50
|
+
);
|
|
51
|
+
const companyFooterText = useMemo(
|
|
52
|
+
() => getRuntimeFooterText(defaultCompany),
|
|
53
|
+
[defaultCompany?.configs],
|
|
54
|
+
);
|
|
55
|
+
const deviceConfigs = useMemo(
|
|
56
|
+
() => parseConfigsObject(deviceConfigItem?.configs),
|
|
57
|
+
[deviceConfigItem?.configs],
|
|
58
|
+
);
|
|
59
|
+
const showDebugInfo = useMemo(
|
|
60
|
+
() =>
|
|
61
|
+
isTruthyValue(
|
|
62
|
+
deviceConfigs?.[DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY],
|
|
63
|
+
),
|
|
64
|
+
[deviceConfigs],
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const entries = useMemo(
|
|
68
|
+
() => [primaryText, companyFooterText].filter(Boolean),
|
|
69
|
+
[companyFooterText, primaryText],
|
|
70
|
+
);
|
|
71
|
+
const inlineText = useMemo(() => entries.join(' • '), [entries]);
|
|
72
|
+
const shouldRotate =
|
|
73
|
+
!showDebugInfo &&
|
|
74
|
+
entries.length > 1 &&
|
|
75
|
+
(width < COMPACT_BREAKPOINT || inlineText.length > MAX_INLINE_TEXT_LENGTH);
|
|
76
|
+
const footerEntries = useMemo(
|
|
77
|
+
() =>
|
|
78
|
+
Object.values(runtimeDebugSummary?.entries || {})
|
|
79
|
+
.filter(entry => entry && Array.isArray(entry.lines) && entry.lines.length > 0)
|
|
80
|
+
.sort((left, right) => {
|
|
81
|
+
const leftOrder = Number(left?.order || 100);
|
|
82
|
+
const rightOrder = Number(right?.order || 100);
|
|
83
|
+
if (leftOrder !== rightOrder) {
|
|
84
|
+
return leftOrder - rightOrder;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const leftTime = Date.parse(left?.updatedAt || '');
|
|
88
|
+
const rightTime = Date.parse(right?.updatedAt || '');
|
|
89
|
+
if (Number.isFinite(leftTime) && Number.isFinite(rightTime)) {
|
|
90
|
+
return rightTime - leftTime;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (Number.isFinite(rightTime)) {
|
|
94
|
+
return 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (Number.isFinite(leftTime)) {
|
|
98
|
+
return -1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return 0;
|
|
102
|
+
}),
|
|
103
|
+
[runtimeDebugSummary?.entries],
|
|
104
|
+
);
|
|
105
|
+
const socketEntry = useMemo(
|
|
106
|
+
() => footerEntries.find(entry => entry?.key === 'socket') || null,
|
|
107
|
+
[footerEntries],
|
|
108
|
+
);
|
|
109
|
+
const debugLines = useMemo(
|
|
110
|
+
() => footerEntries.flatMap(entry => entry?.lines || []),
|
|
111
|
+
[footerEntries],
|
|
112
|
+
);
|
|
113
|
+
const socketIndicatorColor = socketEntry?.indicatorColor;
|
|
114
|
+
const hasStoreLoading = useMemo(
|
|
115
|
+
() =>
|
|
116
|
+
Object.values(allStores || {}).some(
|
|
117
|
+
store =>
|
|
118
|
+
store?.getters?.isLoading === true ||
|
|
119
|
+
store?.getters?.isSaving === true,
|
|
120
|
+
),
|
|
121
|
+
[allStores],
|
|
122
|
+
);
|
|
123
|
+
const bottomInset = Math.max(Number(insets.bottom) || 0, 16);
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (!shouldRotate || entries.length <= 1) {
|
|
127
|
+
setActiveIndex(0);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const intervalId = setInterval(() => {
|
|
132
|
+
setActiveIndex(current => (current + 1) % entries.length);
|
|
133
|
+
}, ROTATION_INTERVAL_MS);
|
|
134
|
+
|
|
135
|
+
return () => {
|
|
136
|
+
clearInterval(intervalId);
|
|
137
|
+
};
|
|
138
|
+
}, [entries.length, shouldRotate]);
|
|
139
|
+
|
|
140
|
+
if (entries.length === 0 && !showDebugInfo) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const displayedText = shouldRotate ? entries[activeIndex] : inlineText;
|
|
145
|
+
const backgroundColor = colors?.background || runtimeColors.background;
|
|
146
|
+
const borderColor = colors?.border || runtimeColors.border;
|
|
147
|
+
const textColor = colors?.textSecondary || runtimeColors.textSecondary;
|
|
148
|
+
const loadingColor = colors?.primary || runtimeColors.primary || textColor;
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<View pointerEvents="none" style={styles.shell}>
|
|
152
|
+
<View
|
|
153
|
+
testID="runtime-info-footer"
|
|
154
|
+
style={[
|
|
155
|
+
styles.container,
|
|
156
|
+
showDebugInfo ? styles.containerExpanded : null,
|
|
157
|
+
{
|
|
158
|
+
backgroundColor,
|
|
159
|
+
borderTopColor: borderColor,
|
|
160
|
+
paddingBottom: bottomInset,
|
|
161
|
+
},
|
|
162
|
+
]}>
|
|
163
|
+
<View style={styles.primaryRow}>
|
|
164
|
+
<View style={styles.statusDotWrap}>
|
|
165
|
+
<View
|
|
166
|
+
style={[
|
|
167
|
+
styles.statusDot,
|
|
168
|
+
{
|
|
169
|
+
backgroundColor: socketIndicatorColor,
|
|
170
|
+
},
|
|
171
|
+
]}
|
|
172
|
+
/>
|
|
173
|
+
</View>
|
|
174
|
+
<Text
|
|
175
|
+
numberOfLines={1}
|
|
176
|
+
ellipsizeMode="tail"
|
|
177
|
+
minimumFontScale={0.85}
|
|
178
|
+
style={[
|
|
179
|
+
styles.primaryText,
|
|
180
|
+
{
|
|
181
|
+
color: textColor,
|
|
182
|
+
},
|
|
183
|
+
]}>
|
|
184
|
+
{showDebugInfo ? inlineText || primaryText || device?.id || '--' : displayedText}
|
|
185
|
+
</Text>
|
|
186
|
+
<View style={styles.loadingWrap}>
|
|
187
|
+
{hasStoreLoading && (
|
|
188
|
+
<ActivityIndicator color={loadingColor} size="small" />
|
|
189
|
+
)}
|
|
190
|
+
</View>
|
|
191
|
+
</View>
|
|
192
|
+
|
|
193
|
+
{showDebugInfo &&
|
|
194
|
+
debugLines.map((line, index) => (
|
|
195
|
+
<Text
|
|
196
|
+
key={`runtime-debug-line-${index}`}
|
|
197
|
+
numberOfLines={1}
|
|
198
|
+
ellipsizeMode="tail"
|
|
199
|
+
minimumFontScale={0.82}
|
|
200
|
+
style={[
|
|
201
|
+
styles.debugText,
|
|
202
|
+
{
|
|
203
|
+
color: textColor,
|
|
204
|
+
},
|
|
205
|
+
]}>
|
|
206
|
+
{line}
|
|
207
|
+
</Text>
|
|
208
|
+
))}
|
|
209
|
+
</View>
|
|
210
|
+
</View>
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export default RuntimeInfoFooter;
|