@controleonline/ui-common 1.2.80 → 1.2.82

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 (90) hide show
  1. package/AGENTS.md +8 -0
  2. package/package.json +9 -3
  3. package/src/api/fetch.js +7 -7
  4. package/src/react/components/AddImportModal.js +6 -2
  5. package/src/react/components/BackgroundRuntimeBridge.js +201 -215
  6. package/src/react/components/ConfirmModal.js +44 -9
  7. package/src/react/components/ConfirmModal.styles.js +55 -41
  8. package/src/react/components/CopyDeviceConfigModal.js +193 -0
  9. package/src/react/components/CopyDeviceConfigModal.styles.js +123 -0
  10. package/src/react/components/DefaultProvider.native.js +22 -0
  11. package/src/react/components/DefaultProvider.web.js +25 -1
  12. package/src/react/components/EntityLogBranch.js +482 -0
  13. package/src/react/components/EntityLogCards.js +369 -0
  14. package/src/react/components/EntityLogContent.js +113 -794
  15. package/src/react/components/LinkedOrderProductsTab.js +3 -3
  16. package/src/react/components/PrintService.js +130 -409
  17. package/src/react/components/RemoteCheckoutService.js +2 -2
  18. package/src/react/components/RuntimeBottomNavigationBar.js +141 -146
  19. package/src/react/components/RuntimeFooterMarqueeText.js +137 -0
  20. package/src/react/components/RuntimeInfoFooter.js +12 -15
  21. package/src/react/components/SystemErrorToast.js +49 -29
  22. package/src/react/components/SystemErrorToast.styles.js +43 -38
  23. package/src/react/components/UserAvatar.js +120 -28
  24. package/src/react/config/deviceConfigBootstrap.js +330 -304
  25. package/src/react/hooks/usePrintSpoolEffects.js +161 -0
  26. package/src/react/pages/DeviceDetailPage.js +6 -2882
  27. package/src/react/pages/Devices/detail/DeviceDetailAlertsCommandsSection.js +233 -0
  28. package/src/react/pages/Devices/detail/DeviceDetailHeader.js +138 -0
  29. package/src/react/pages/Devices/detail/DeviceDetailMovementSections.js +167 -0
  30. package/src/react/pages/Devices/detail/DeviceDetailOrdersPrintSection.js +216 -0
  31. package/src/react/pages/Devices/detail/DeviceDetailPaymentSection.js +44 -0
  32. package/src/react/pages/Devices/detail/DeviceDetailPdvConfigSection.js +390 -0
  33. package/src/react/pages/Devices/detail/DeviceDetailRenderers.js +135 -0
  34. package/src/react/pages/Devices/detail/DeviceDetailScreen.js +495 -0
  35. package/src/react/pages/Devices/detail/OptionButtonChip.js +65 -0
  36. package/src/react/pages/Devices/detail/deviceDetailConstants.js +36 -0
  37. package/src/react/pages/Devices/detail/deviceDetailHelpers.js +70 -0
  38. package/src/react/pages/Devices/detail/useDeviceDetailActions.js +483 -0
  39. package/src/react/pages/Devices/detail/useDeviceDetailCopyConfig.js +87 -0
  40. package/src/react/pages/Devices/detail/useDeviceDetailLoaders.js +327 -0
  41. package/src/react/pages/Devices/detail/useDeviceDetailSaves.js +429 -0
  42. package/src/react/pages/Devices/detail/useDeviceDetailStateA.js +489 -0
  43. package/src/react/pages/Devices/detail/useDeviceDetailStateB.js +98 -0
  44. package/src/react/pages/Devices/deviceTypes/index.js +2 -0
  45. package/src/react/pages/Devices/deviceTypes/pdv.js +11 -0
  46. package/src/react/pages/Imports.js +3 -2
  47. package/src/react/pages/IntegrationConfigFields.js +126 -0
  48. package/src/react/pages/IntegrationConfigPage.js +122 -591
  49. package/src/react/pages/IntegrationConfigPage.utils.js +95 -0
  50. package/src/react/print/usePrintButtonController.js +9 -1
  51. package/src/react/services/Getnet/Checkout.js +81 -0
  52. package/src/react/services/Getnet/Getnet.js +77 -0
  53. package/src/react/services/paymentGatewayExecution.js +20 -0
  54. package/src/react/utils/bottomNavigationToolbar.js +161 -0
  55. package/src/react/utils/commercialDocumentOrders.js +18 -6
  56. package/src/react/utils/copyDeviceConfigs.js +198 -0
  57. package/src/react/utils/fileUrl.js +43 -0
  58. package/src/react/utils/importStatus.js +19 -10
  59. package/src/react/utils/logSettings.js +7 -7
  60. package/src/react/utils/maintenanceSettings.js +16 -0
  61. package/src/react/utils/paymentDevices.js +6 -0
  62. package/src/react/utils/printManagedPrinter.js +45 -0
  63. package/src/react/utils/printRouting.js +63 -0
  64. package/src/react/utils/printSpoolUtils.js +119 -0
  65. package/src/react/utils/printerDevices.js +368 -368
  66. package/src/react/utils/runtimeFooter.js +10 -19
  67. package/src/react/utils/shopFranchises.js +186 -65
  68. package/src/react/utils/systemErrorMessage.js +71 -67
  69. package/src/store/device_config/customActions.js +119 -30
  70. package/src/tests/browser/manager/bottom-navigation-role-toolbar.spec.js +353 -0
  71. package/src/tests/browser/manager/device-detail-alias-save.spec.js +345 -0
  72. package/src/tests/browser/manager/device-detail-copy-config.spec.js +365 -0
  73. package/src/tests/browser/manager/runtime-footer-marquee.spec.js +262 -0
  74. package/src/tests/browser/manager/theme-confirm-toast.spec.js +236 -0
  75. package/src/tests/react/components/RuntimeFooterMarqueeText.test.js +171 -0
  76. package/src/tests/react/components/UserAvatar.test.js +6 -2
  77. package/src/tests/react/components/themeAwareModals.test.mjs +60 -0
  78. package/src/tests/react/config/deviceConfigBootstrap.test.js +104 -66
  79. package/src/tests/react/pages/deviceDetailDelete.test.js +78 -0
  80. package/src/tests/react/pages/receitaFederalIntegrationContract.test.mjs +48 -0
  81. package/src/tests/react/utils/bottomNavigationToolbar.test.js +222 -0
  82. package/src/tests/react/utils/copyDeviceConfigs.test.mjs +127 -0
  83. package/src/tests/react/utils/fileUrl.test.js +38 -0
  84. package/src/tests/react/utils/importStatus.test.js +26 -9
  85. package/src/tests/react/utils/passwordPolicy.test.js +27 -0
  86. package/src/tests/react/utils/printRouting.test.mjs +86 -0
  87. package/src/tests/react/utils/printSpoolUtils.test.mjs +52 -0
  88. package/src/tests/react/utils/runtimeFooter.test.js +7 -0
  89. package/src/tests/react/utils/shopFranchises.test.js +121 -115
  90. package/src/tests/react/utils/systemErrorMessage.test.js +32 -59
@@ -0,0 +1,135 @@
1
+ import React from 'react';
2
+ import { Text, View, Switch } from 'react-native';
3
+ import DefaultTooltip from '@controleonline/ui-default/src/react/components/help/DefaultTooltip';
4
+ import Formatter from '@controleonline/ui-common/src/utils/formatter';
5
+ import styles from '../../DeviceDetailPage.styles';
6
+ import { inlineStyle_667_12 } from '../../DeviceDetailPage.styles';
7
+ import OptionButtonChip from './OptionButtonChip';
8
+ import { getDeviceSwitchProps } from './deviceDetailHelpers';
9
+
10
+ /** Factory so themeColors/palette close over caller context */
11
+ export function createDeviceDetailRenderers({ themeColors, palette }) {
12
+ const renderProduct = ({ item, index }) => (
13
+ <View style={[styles.productRow, index % 2 === 0 && styles.productRowAlt]}>
14
+ <Text style={[styles.productCell, { flex: 0.5 }]}>{item.quantity}</Text>
15
+ <View style={inlineStyle_667_12}>
16
+ <Text style={styles.productName} numberOfLines={1}>{item.product_name}</Text>
17
+ {!!item.product_sku && (
18
+ <Text style={styles.productSku}>{item.product_sku}</Text>
19
+ )}
20
+ </View>
21
+ <Text style={[styles.productCell, { flex: 1.2, textAlign: 'right' }]}>
22
+ {Formatter.formatMoney(item.order_product_price)}
23
+ </Text>
24
+ <Text style={[styles.productCell, { flex: 1.3, textAlign: 'right', fontWeight: '700' }]}>
25
+ {Formatter.formatMoney(item.order_product_total)}
26
+ </Text>
27
+ </View>
28
+ );
29
+
30
+ const renderHelpButton = (title, message) => (
31
+ <DefaultTooltip
32
+ accentColor={themeColors.buttonIcon}
33
+ title={title}
34
+ message={message}
35
+ style={{
36
+ backgroundColor: themeColors.buttonBackground,
37
+ borderColor: themeColors.buttonBackground,
38
+ borderRadius: 8,
39
+ height: 34,
40
+ width: 34,
41
+ }}
42
+ textStyle={{
43
+ color: themeColors.buttonIcon,
44
+ fontSize: 16,
45
+ lineHeight: 16,
46
+ }}
47
+ />
48
+ );
49
+
50
+ const renderSwitchRow = ({
51
+ disabled = false,
52
+ label,
53
+ onValueChange,
54
+ value,
55
+ valueLabel,
56
+ }) => {
57
+ const checked = Boolean(value);
58
+
59
+ return (
60
+ <View
61
+ style={[
62
+ styles.toggleRow,
63
+ {
64
+ backgroundColor: themeColors.listItemBackground,
65
+ borderColor: themeColors.listItemBorder,
66
+ },
67
+ disabled && styles.toggleRowDisabled,
68
+ ]}>
69
+ <View style={styles.toggleRowCopy}>
70
+ <Text
71
+ style={[
72
+ styles.toggleRowLabel,
73
+ {color: themeColors.listItemText},
74
+ ]}>
75
+ {label}
76
+ </Text>
77
+ <Text
78
+ style={[
79
+ styles.toggleRowValue,
80
+ {color: themeColors.listItemSubtitleText},
81
+ ]}>
82
+ {valueLabel}
83
+ </Text>
84
+ </View>
85
+ <Switch
86
+ value={checked}
87
+ disabled={disabled}
88
+ onValueChange={onValueChange}
89
+ {...getDeviceSwitchProps({
90
+ disabled,
91
+ palette: themeColors,
92
+ value: checked,
93
+ })}
94
+ />
95
+ </View>
96
+ );
97
+ };
98
+
99
+ const renderOptionButtons = ({ options, value, onChange, disabled = false, optionColors = null }) => (
100
+ <View style={styles.optionRow}>
101
+ {options.map(option => {
102
+ const selected = String(option.value) === String(value);
103
+ const optionDisabled = disabled || option.disabled === true;
104
+ const optionTitle = String(option.title || '').trim();
105
+ if (optionDisabled && optionTitle) {
106
+ return (
107
+ <OptionButtonChip
108
+ key={String(option.value)}
109
+ label={option.label}
110
+ selected={selected}
111
+ disabled
112
+ colors={optionColors}
113
+ tooltip={optionTitle}
114
+ onPress={() => onChange(option.value)}
115
+ />
116
+ );
117
+ }
118
+
119
+ return (
120
+ <OptionButtonChip
121
+ key={String(option.value)}
122
+ label={option.label}
123
+ selected={selected}
124
+ disabled={optionDisabled}
125
+ colors={optionColors}
126
+ tooltip={optionTitle}
127
+ onPress={() => onChange(option.value)}
128
+ />
129
+ );
130
+ })}
131
+ </View>
132
+ );
133
+
134
+ return { renderProduct, renderHelpButton, renderSwitchRow, renderOptionButtons };
135
+ }
@@ -0,0 +1,495 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { Alert, FlatList, Platform, Pressable, ScrollView, Switch, Text, TextInput, TouchableOpacity, View } from 'react-native';
3
+ import { SafeAreaView } from 'react-native-safe-area-context';
4
+ import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
5
+ import {Picker} from '@react-native-picker/picker';
6
+ import { useStore } from '@store';
7
+ import { api } from '@controleonline/ui-common/src/api';
8
+ import Formatter from '@controleonline/ui-common/src/utils/formatter';
9
+ import StateStore from '@controleonline/ui-common/src/react/components/StateStore';
10
+ import PaymentTypesByWalletTab from '@controleonline/ui-common/src/react/pages/SettingsPage/PaymentTypesByWalletTab';
11
+ import { appendScreenMetrics } from '@controleonline/ui-common/src/react/utils/screenMetrics';
12
+ import { useMessage } from '@controleonline/ui-common/src/react/components/MessageService';
13
+ import { resolveThemePalette, withOpacity } from '@controleonline/../../src/styles/branding';
14
+ import { colors } from '@controleonline/../../src/styles/colors';
15
+ import Icon from 'react-native-vector-icons/Feather';
16
+ import styles from '../../DeviceDetailPage.styles';
17
+ import packageJson from '@package';
18
+ import DefaultTooltip from '@controleonline/ui-default/src/react/components/help/DefaultTooltip';
19
+
20
+ import {
21
+ canDisplayChangePrinter,
22
+ DEVICE_ANDROID_KIOSK_ENABLED_CONFIG_KEY,
23
+ DEVICE_ANDROID_LAUNCHER_ENABLED_CONFIG_KEY,
24
+ DISPLAY_AUTO_PRINT_PRODUCT_CONFIG_KEY,
25
+ DISPLAY_ALLOW_PRINTER_CHANGE_CONFIG_KEY,
26
+ DEVICE_ALERT_SOUND_ENABLED_KEY,
27
+ DEVICE_ALERT_SOUND_URL_KEY,
28
+ DEVICE_ORDER_VISIBILITY_COMPANY,
29
+ DEVICE_ORDER_VISIBILITY_DEVICE,
30
+ DEVICE_ORDER_VISIBILITY_KEY,
31
+ DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY,
32
+ isPosAutoPrintEnabled,
33
+ isPosCashRegisterOpen,
34
+ isTruthyValue,
35
+ parseConfigsObject,
36
+ POS_AUTO_PRINT_ENABLED_CONFIG_KEY,
37
+ POS_CASH_MANAGEMENT_MODE_CASH_REGISTER,
38
+ POS_CASH_MANAGEMENT_MODE_CONFIG_KEY,
39
+ POS_CASH_MANAGEMENT_MODE_DAILY,
40
+ POS_CHECK_ORDER_MANAGEMENT_MODE_CONFIG_KEY,
41
+ POS_CHECK_ORDER_MANAGEMENT_MODE_EXISTING_ONLY,
42
+ POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE,
43
+ POS_CHECK_ORDER_TYPE_CONFIG_KEY,
44
+ POS_CHECK_ORDER_TYPE_NONE,
45
+ POS_CHECK_ORDER_TYPE_TAB,
46
+ POS_CHECK_ORDER_TYPE_TABLE,
47
+ POS_CHECK_ORDER_TYPE_STAMP,
48
+ POS_DELIVERY_ENABLED_CONFIG_KEY,
49
+ POS_OPERATION_MODE_COUNTER,
50
+ POS_OPERATION_MODE_CONFIG_KEY,
51
+ POS_OPERATION_MODE_OPTIONS,
52
+ POS_PRODUCT_SHOWCASE_CONFIG_KEY,
53
+ POS_PRINT_MODE_FORM,
54
+ POS_PRINT_MODE_ORDER,
55
+ getPosOperationModeOption,
56
+ isAndroidKioskEnabled,
57
+ isAndroidLauncherEnabled,
58
+ isPosDeliveryEnabled,
59
+ resolvePosCheckOrderManagementMode,
60
+ resolvePosCheckOrderType,
61
+ resolvePosCheckOrderTypeForShop,
62
+ resolveDeviceOrderVisibility,
63
+ resolvePosCashManagementMode,
64
+ resolvePosOperationMode,
65
+ resolvePosPrintMode,
66
+ } from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
67
+
68
+ import {
69
+ filterDeviceConfigsByCompany,
70
+ getCompanyPaymentDeviceOptions,
71
+ getPaymentGatewayFromConfigs,
72
+ getPaymentGatewayLabel,
73
+ isPaymentCapableDeviceConfig,
74
+ isPdvPrinterEnabled,
75
+ normalizeDeviceId,
76
+ normalizeEntityId,
77
+ PAYMENT_TYPE_IDS_CONFIG_KEY,
78
+ PAYMENT_GATEWAY_CIELO,
79
+ PDV_PRINTER_ENABLED_CONFIG_KEY,
80
+ ORDER_PAYMENT_DEVICE_CONFIG_KEY,
81
+ POS_GATEWAY_CONFIG_KEY,
82
+ } from '@controleonline/ui-common/src/react/utils/paymentDevices';
83
+ import {
84
+ normalizeBooleanConfig,
85
+ SHOP_LOYALTY_COUPONS_ENABLED_CONFIG_KEY,
86
+ } from '@controleonline/ui-common/src/react/utils/shopConfig';
87
+
88
+ import {
89
+ getPrinterOptionValue,
90
+ getDeviceTypeLabel,
91
+ getPrinterLabel,
92
+ getPrinterOptions,
93
+ } from '@controleonline/ui-common/src/react/utils/printerDevices';
94
+ import { buildDeviceAliasStoreUpdates } from '@controleonline/ui-common/src/react/utils/deviceAliasSync';
95
+ import { createDeviceDetailRenderers } from './DeviceDetailRenderers';
96
+ import DeviceDetailHeader from './DeviceDetailHeader';
97
+ import CopyDeviceConfigModal from '@controleonline/ui-common/src/react/components/CopyDeviceConfigModal';
98
+ import useDeviceDetailCopyConfig from './useDeviceDetailCopyConfig';
99
+ import DeviceDetailPdvConfigSection from './DeviceDetailPdvConfigSection';
100
+ import DeviceDetailOrdersPrintSection from './DeviceDetailOrdersPrintSection';
101
+ import DeviceDetailAlertsCommandsSection from './DeviceDetailAlertsCommandsSection';
102
+ import DeviceDetailMovementSections from './DeviceDetailMovementSections';
103
+ import DeviceDetailPaymentSection from './DeviceDetailPaymentSection';
104
+
105
+ import { inlineStyle_667_12, inlineStyle_1301_61 } from '../../DeviceDetailPage.styles';
106
+
107
+ import {
108
+ hex,
109
+ DISPLAY_DEVICE_TYPE,
110
+ PDV_DEVICE_TYPE,
111
+ DISPLAY_DEVICE_LINK_CONFIG_KEY,
112
+ DISPLAY_DEVICE_PRINTER_CONFIG_KEY,
113
+ PDV_TAB_OPERATION,
114
+ PDV_TAB_ORDERS,
115
+ PDV_TAB_DEVICE,
116
+ PDV_TAB_PAYMENT_TYPES,
117
+ PDV_TAB_MOVEMENT,
118
+ PDV_DETAIL_TABS,
119
+ tt,
120
+ } from './deviceDetailConstants';
121
+ import {
122
+ paymentIcon,
123
+ formatApiError,
124
+ getDisplayLabel,
125
+ getProductShowcaseLabel,
126
+ getIsOpen,
127
+ confirm,
128
+ getDeviceSwitchProps,
129
+ } from './deviceDetailHelpers';
130
+ import OptionButtonChip from './OptionButtonChip';
131
+
132
+
133
+ import useDeviceDetailStateA from './useDeviceDetailStateA';
134
+ import useDeviceDetailStateB from './useDeviceDetailStateB';
135
+ import useDeviceDetailLoaders from './useDeviceDetailLoaders';
136
+ import useDeviceDetailActions from './useDeviceDetailActions';
137
+ import useDeviceDetailSaves from './useDeviceDetailSaves';
138
+
139
+ const DeviceDetailScreen = () => {
140
+ const stateA = useDeviceDetailStateA();
141
+ const stateB = useDeviceDetailStateB(stateA);
142
+ const state = { ...stateA, ...stateB };
143
+ const loaders = useDeviceDetailLoaders(state);
144
+ const actions = useDeviceDetailActions({ ...state, ...loaders });
145
+ const saves = useDeviceDetailSaves({ ...state, ...loaders, ...actions });
146
+ const {
147
+ navigation,
148
+ deviceId,
149
+ deviceConfigStore,
150
+ messageApi,
151
+ websocketActions,
152
+ runtimeCompanyConfigs,
153
+ showSystemError,
154
+ loyaltyCouponsEnabled,
155
+ currentDevice,
156
+ currentDeviceConfig,
157
+ deviceString,
158
+ deviceType,
159
+ normalizedInitialConfigs,
160
+ initialAlias,
161
+ isDisplayDevice,
162
+ isPdvDevice,
163
+ actionsRef,
164
+ stampAutoDisableSignatureRef,
165
+ brandColors,
166
+ products,
167
+ setProducts,
168
+ productShowcases,
169
+ setProductShowcases,
170
+ companyDeviceConfigs,
171
+ setCompanyDeviceConfigs,
172
+ inflowData,
173
+ setInflowData,
174
+ configs,
175
+ setConfigs,
176
+ loadingConfigData,
177
+ setLoadingConfigData,
178
+ loadingCompanyDeviceConfigs,
179
+ setLoadingCompanyDeviceConfigs,
180
+ loadingMovementData,
181
+ setLoadingMovementData,
182
+ actionLoading,
183
+ setActionLoading,
184
+ activePdvTab,
185
+ setActivePdvTab,
186
+ savingPaymentTarget,
187
+ setSavingPaymentTarget,
188
+ savingPdvSettings,
189
+ setSavingPdvSettings,
190
+ savingPaymentTypes,
191
+ setSavingPaymentTypes,
192
+ savingPosOperationMode,
193
+ setSavingPosOperationMode,
194
+ savingProductShowcase,
195
+ setSavingProductShowcase,
196
+ savingLauncherMode,
197
+ setSavingLauncherMode,
198
+ savingAlertSound,
199
+ setSavingAlertSound,
200
+ savingOrderVisibility,
201
+ setSavingOrderVisibility,
202
+ savingDeviceDeliverySettings,
203
+ setSavingDeviceDeliverySettings,
204
+ savingRuntimeDebugInfo,
205
+ setSavingRuntimeDebugInfo,
206
+ sendingCatalogRefresh,
207
+ setSendingCatalogRefresh,
208
+ loadingProductShowcases,
209
+ setLoadingProductShowcases,
210
+ search,
211
+ setSearch,
212
+ devicePaymentTarget,
213
+ setDevicePaymentTarget,
214
+ pdvGateway,
215
+ setPdvGateway,
216
+ pdvPrinterEnabled,
217
+ setPdvPrinterEnabled,
218
+ posOperationMode,
219
+ setPosOperationMode,
220
+ productShowcaseId,
221
+ setProductShowcaseId,
222
+ androidKioskEnabled,
223
+ setAndroidKioskEnabled,
224
+ androidLauncherEnabled,
225
+ setAndroidLauncherEnabled,
226
+ counterAutoPrintEnabled,
227
+ setCounterAutoPrintEnabled,
228
+ counterPrintMode,
229
+ setCounterPrintMode,
230
+ counterCashManagementMode,
231
+ setCounterCashManagementMode,
232
+ checkOrderType,
233
+ setCheckOrderType,
234
+ checkOrderManagementMode,
235
+ setCheckOrderManagementMode,
236
+ deviceOrderVisibility,
237
+ setDeviceOrderVisibility,
238
+ deviceDeliveryEnabled,
239
+ setDeviceDeliveryEnabled,
240
+ deviceAlertSoundEnabled,
241
+ setDeviceAlertSoundEnabled,
242
+ deviceAlertSoundUrl,
243
+ setDeviceAlertSoundUrl,
244
+ deviceRuntimeDebugInfoEnabled,
245
+ setDeviceRuntimeDebugInfoEnabled,
246
+ linkedDisplayId,
247
+ setLinkedDisplayId,
248
+ displayPrinterId,
249
+ setDisplayPrinterId,
250
+ displayAllowPrinterChange,
251
+ setDisplayAllowPrinterChange,
252
+ displayAutoPrintProductEnabled,
253
+ setDisplayAutoPrintProductEnabled,
254
+ savingDisplayPrintingConfig,
255
+ setSavingDisplayPrintingConfig,
256
+ hasLoadedCurrentConfig,
257
+ setHasLoadedCurrentConfig,
258
+ hasLoadedCompanyConfigs,
259
+ setHasLoadedCompanyConfigs,
260
+ hasLoadedMovementData,
261
+ setHasLoadedMovementData,
262
+ hasLoadedCurrentConfigRef,
263
+ hasLoadedCompanyConfigsRef,
264
+ hasLoadedMovementDataRef,
265
+ hasInitializedPdvTabRef,
266
+ alias,
267
+ setAlias,
268
+ editingAlias,
269
+ setEditingAlias,
270
+ aliasInput,
271
+ setAliasInput,
272
+ savingAlias,
273
+ setSavingAlias,
274
+ removingDevice,
275
+ setRemovingDevice,
276
+ aliasInputRef,
277
+ skipAliasSyncFromStoreRef,
278
+ isOpen,
279
+ hasLocalPaymentGateway,
280
+ paymentDeviceOptions,
281
+ displayOptions,
282
+ printerOptions,
283
+ selectedPosOperationModeOption,
284
+ pickerMode,
285
+ packageVersion,
286
+ appVersion,
287
+ runtimeDeviceId,
288
+ runtimeDeviceType,
289
+ isEditingRuntimeDevice,
290
+ resolveDeviceContext,
291
+ applyCurrentDeviceConfig,
292
+ loadMovementData,
293
+ refreshCurrentConfig,
294
+ loadCompanyConfigs,
295
+ loadProductShowcases,
296
+ ensureActiveTabData,
297
+ ensureActiveTabDataRef,
298
+ handleToggle,
299
+ startEditAlias,
300
+ cancelEditAlias,
301
+ saveAlias,
302
+ confirmRemoveDevice,
303
+ saveDevicePaymentTarget,
304
+ savePdvSettings,
305
+ saveProductShowcaseConfig,
306
+ savePaymentTypeConfigs,
307
+ savePosOperationMode,
308
+ saveLauncherMode,
309
+ saveDeviceAlertSoundConfig,
310
+ saveDeviceOrderVisibility,
311
+ saveDeviceDeliverySettings,
312
+ saveDeviceRuntimeDebugInfo,
313
+ saveDisplayPrintingConfig,
314
+ sendCatalogRefreshCommand,
315
+ productTotal,
316
+ inflowTotal,
317
+ wallets,
318
+ filteredProducts,
319
+ accent,
320
+ showPdvOperationTab,
321
+ showPdvOrdersTab,
322
+ showPdvDeviceTab,
323
+ showPdvPaymentTypesTab,
324
+ showPdvMovementTab,
325
+ loadingActiveTabData,
326
+ shouldShowOrderVisibility,
327
+ shouldShowRemotePayment,
328
+ shouldShowDeviceBehavior,
329
+ shouldShowRemoteCommands,
330
+ currentCompany,
331
+ } = { ...state, ...loaders, ...actions, ...saves };
332
+
333
+ const detailCtx = {
334
+ themeColors, brandColors, palette,
335
+ renderHelpButton, renderOptionButtons, renderSwitchRow, renderProduct,
336
+ posOperationMode, setPosOperationMode, savePosOperationMode, savingPosOperationMode,
337
+ productShowcaseId, setProductShowcaseId, saveProductShowcaseConfig,
338
+ productShowcases, loadingProductShowcases, savingProductShowcase, pickerMode,
339
+ counterAutoPrintEnabled, setCounterAutoPrintEnabled,
340
+ counterPrintMode, setCounterPrintMode,
341
+ checkOrderType, setCheckOrderType,
342
+ checkOrderManagementMode, setCheckOrderManagementMode,
343
+ cashManagementMode, setCashManagementMode,
344
+ androidKioskEnabled, setAndroidKioskEnabled,
345
+ androidLauncherEnabled, setAndroidLauncherEnabled,
346
+ saveLauncherMode, savingLauncherMode,
347
+ orderVisibility, setOrderVisibility, saveDeviceOrderVisibility, savingOrderVisibility,
348
+ shouldShowOrderVisibility,
349
+ deliveryEnabled, setDeliveryEnabled, saveDeviceDeliverySettings, savingDeliverySettings,
350
+ deviceAlertSoundEnabled, setDeviceAlertSoundEnabled, deviceAlertSoundUrl, setDeviceAlertSoundUrl,
351
+ saveDeviceAlertSoundConfig, savingAlertSound,
352
+ runtimeDebugInfoEnabled, setRuntimeDebugInfoEnabled, saveDeviceRuntimeDebugInfo, savingRuntimeDebugInfo,
353
+ devicePaymentTarget, setDevicePaymentTarget, saveDevicePaymentTarget, savingPaymentTarget,
354
+ paymentDeviceOptions, displayOptions, printerOptions,
355
+ pdvGateway, setPdvGateway, pdvPrinterEnabled, setPdvPrinterEnabled, savePdvSettings, savingPdvSettings,
356
+ hasLocalPaymentGateway, loyaltyCouponsEnabled,
357
+ sendCatalogRefreshCommand, sendingCatalogRefresh,
358
+ showPdvMovementTab, showPdvPaymentTypesTab, showPdvOperationTab,
359
+ inflowData, productTotal, wallets, filteredProducts, search, setSearch,
360
+ loadingMovementData, deviceId, savePaymentTypeConfigs, savingPaymentTypes,
361
+ configs, currentCompany,
362
+ };
363
+
364
+ const {
365
+ copyModalVisible,
366
+ copyingConfig,
367
+ openCopyConfigModal,
368
+ closeCopyConfigModal,
369
+ handleCopyConfigConfirm,
370
+ } = useDeviceDetailCopyConfig({
371
+ actionsRef,
372
+ alias,
373
+ currentCompanyId: currentCompany?.id,
374
+ deviceString,
375
+ loadCompanyConfigs,
376
+ messageApi,
377
+ refreshCurrentConfig,
378
+ showSystemError,
379
+ });
380
+
381
+
382
+ return (
383
+ <SafeAreaView style={[styles.container, { backgroundColor: brandColors.background }]}>
384
+ <ScrollView contentContainerStyle={styles.scroll} showsVerticalScrollIndicator={false}>
385
+ <DeviceDetailHeader
386
+ accent={accent}
387
+ alias={alias}
388
+ aliasInput={aliasInput}
389
+ aliasInputRef={aliasInputRef}
390
+ deviceId={deviceId}
391
+ deviceString={deviceString}
392
+ editingAlias={editingAlias}
393
+ removingDevice={removingDevice}
394
+ savingAlias={savingAlias}
395
+ themeColors={themeColors}
396
+ onAliasChange={setAliasInput}
397
+ onConfirmRemove={confirmRemoveDevice}
398
+ onCopyConfig={openCopyConfigModal}
399
+ copyingConfig={copyingConfig}
400
+ onSaveAlias={saveAlias}
401
+ onStartEdit={startEditAlias}
402
+ />
403
+
404
+ {loadingActiveTabData && (
405
+ <StateStore
406
+ compact
407
+ loading="Carregando dados do device..."
408
+ />
409
+ )}
410
+
411
+ {isPdvDevice && (
412
+ <View style={styles.tabsBar}>
413
+ <ScrollView
414
+ horizontal
415
+ showsHorizontalScrollIndicator={false}
416
+ contentContainerStyle={styles.tabsContent}>
417
+ {PDV_DETAIL_TABS.map(tab => {
418
+ const active = activePdvTab === tab.key;
419
+ const tabButtonColors = active
420
+ ? {
421
+ backgroundColor: themeColors.buttonBackground,
422
+ borderColor: themeColors.buttonBorder,
423
+ iconColor: themeColors.buttonIcon,
424
+ textColor: themeColors.buttonText,
425
+ }
426
+ : {
427
+ backgroundColor: themeColors.buttonBackgroundSecondary,
428
+ borderColor: themeColors.buttonBorderSecondary,
429
+ iconColor: themeColors.buttonIconSecondary,
430
+ textColor: themeColors.buttonTextSecondary,
431
+ };
432
+
433
+ return (
434
+ <TouchableOpacity
435
+ key={tab.key}
436
+ style={[
437
+ styles.tabButton,
438
+ {
439
+ backgroundColor: tabButtonColors.backgroundColor,
440
+ borderColor: tabButtonColors.borderColor,
441
+ },
442
+ ]}
443
+ activeOpacity={0.85}
444
+ onPress={() => setActivePdvTab(tab.key)}>
445
+ <Icon
446
+ name={tab.icon}
447
+ size={14}
448
+ color={tabButtonColors.iconColor}
449
+ />
450
+ <Text
451
+ style={[
452
+ styles.tabButtonText,
453
+ {color: tabButtonColors.textColor},
454
+ ]}>
455
+ {tt('tab', tab.labelKey) ||
456
+ (tab.key === PDV_TAB_PAYMENT_TYPES
457
+ ? 'Pagamentos'
458
+ : tab.labelKey)}
459
+ </Text>
460
+ </TouchableOpacity>
461
+ );
462
+ })}
463
+ </ScrollView>
464
+ </View>
465
+ )}
466
+
467
+ <DeviceDetailMovementSections {...detailCtx} />
468
+
469
+ {showPdvOperationTab && (
470
+ <>
471
+ <DeviceDetailPdvConfigSection {...detailCtx} />
472
+ <DeviceDetailOrdersPrintSection {...detailCtx} />
473
+ <DeviceDetailAlertsCommandsSection {...detailCtx} />
474
+ </>
475
+ )}
476
+
477
+ <DeviceDetailPaymentSection {...detailCtx} />
478
+
479
+ </ScrollView>
480
+ <CopyDeviceConfigModal
481
+ visible={copyModalVisible}
482
+ onClose={closeCopyConfigModal}
483
+ onConfirm={handleCopyConfigConfirm}
484
+ companyDeviceConfigs={companyDeviceConfigs}
485
+ companyId={currentCompany?.id}
486
+ destinationDeviceString={deviceString}
487
+ destinationAlias={alias}
488
+ loading={loadingCompanyDeviceConfigs}
489
+ confirming={copyingConfig}
490
+ />
491
+ </SafeAreaView>
492
+ );
493
+ };
494
+
495
+ export default DeviceDetailScreen;
@@ -0,0 +1,65 @@
1
+ import React, {useState} from 'react';
2
+ import {Platform, Pressable, Text, TouchableOpacity, View} from 'react-native';
3
+ import styles from '../../DeviceDetailPage.styles';
4
+
5
+ const OptionButtonChip = ({
6
+ label,
7
+ selected,
8
+ disabled,
9
+ colors: optionColors,
10
+ tooltip,
11
+ onPress,
12
+ }) => {
13
+ const [hovered, setHovered] = useState(false);
14
+ const showTooltip =
15
+ Platform.OS === 'web' && disabled && Boolean(tooltip) && hovered;
16
+
17
+ return (
18
+ <Pressable
19
+ onHoverIn={() => setHovered(true)}
20
+ onHoverOut={() => setHovered(false)}
21
+ style={[
22
+ styles.optionButtonHoverWrap,
23
+ hovered && styles.optionButtonHoverWrapActive,
24
+ ]}>
25
+ <TouchableOpacity
26
+ style={[
27
+ styles.optionButton,
28
+ selected && styles.optionButtonActive,
29
+ optionColors && {
30
+ backgroundColor: selected
31
+ ? optionColors.buttonBackground
32
+ : optionColors.buttonBackgroundSecondary,
33
+ borderColor: selected
34
+ ? optionColors.buttonBorder
35
+ : optionColors.buttonBorderSecondary,
36
+ },
37
+ disabled && {opacity: 0.55},
38
+ ]}
39
+ accessibilityHint={tooltip || undefined}
40
+ activeOpacity={disabled ? 1 : 0.85}
41
+ disabled={disabled}
42
+ onPress={disabled ? undefined : onPress}>
43
+ <Text
44
+ style={[
45
+ styles.optionButtonText,
46
+ selected && styles.optionButtonTextActive,
47
+ optionColors && {
48
+ color: selected
49
+ ? optionColors.buttonText
50
+ : optionColors.buttonTextSecondary,
51
+ },
52
+ ]}>
53
+ {label}
54
+ </Text>
55
+ </TouchableOpacity>
56
+ {showTooltip ? (
57
+ <View pointerEvents="none" style={styles.optionButtonTooltip}>
58
+ <Text style={styles.optionButtonTooltipText}>{tooltip}</Text>
59
+ </View>
60
+ ) : null}
61
+ </Pressable>
62
+ );
63
+ };
64
+
65
+ export default OptionButtonChip;