@controleonline/ui-common 1.2.80 → 1.2.81

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 +40 -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 +493 -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 +484 -0
  43. package/src/react/pages/Devices/detail/useDeviceDetailStateB.js +71 -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,216 @@
1
+ import React from 'react';
2
+ import {Text, View} from 'react-native';
3
+ import {Picker} from '@react-native-picker/picker';
4
+ import Icon from 'react-native-vector-icons/Feather';
5
+ import styles from '../../DeviceDetailPage.styles';
6
+ import {
7
+ DEVICE_ORDER_VISIBILITY_COMPANY,
8
+ DEVICE_ORDER_VISIBILITY_DEVICE,
9
+ } from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
10
+ import {
11
+ normalizeEntityId,
12
+ normalizeDeviceId,
13
+ } from '@controleonline/ui-common/src/react/utils/paymentDevices';
14
+ import {getDisplayLabel} from './deviceDetailHelpers';
15
+ import {tt} from './deviceDetailConstants';
16
+
17
+ /**
18
+ * Pedidos do device + impressão de preparo (DISPLAY).
19
+ * Extraído de DeviceDetailScreen (app-community#382 / hotfix #645).
20
+ */
21
+ export default function DeviceDetailOrdersPrintSection(ctx) {
22
+ const {
23
+ themeColors,
24
+ renderHelpButton,
25
+ renderOptionButtons,
26
+ renderSwitchRow,
27
+ orderVisibility,
28
+ setOrderVisibility,
29
+ saveDeviceOrderVisibility,
30
+ deliveryEnabled,
31
+ setDeliveryEnabled,
32
+ saveDeviceDeliverySettings,
33
+ savingDeliverySettings,
34
+ displayAutoPrintProduct,
35
+ setDisplayAutoPrintProduct,
36
+ displayAllowPrinterChange,
37
+ setDisplayAllowPrinterChange,
38
+ saveDisplayPrintingConfig,
39
+ savingDisplayPrinting,
40
+ linkedDisplayId,
41
+ setLinkedDisplayId,
42
+ displayOptions,
43
+ printerOptions,
44
+ pickerMode,
45
+ isDisplayDevice,
46
+ } = ctx;
47
+
48
+ const printerLabel = option => {
49
+ const id = normalizeDeviceId(option?.device || option);
50
+ const name = String(option?.name || option?.deviceName || option?.label || '').trim();
51
+ return name ? `${name} (${id})` : `Impressora ${id || '--'}`;
52
+ };
53
+
54
+ return (
55
+ <>
56
+ <View style={styles.section}>
57
+ <Text style={styles.sectionTitle}>
58
+ <Icon name="list" size={13} /> {' '}Pedidos do Device
59
+ </Text>
60
+
61
+ <View style={styles.configCard}>
62
+ <View style={styles.sectionTitleRow}>
63
+ <Text style={styles.configTitle}>Escopo da listagem no PDV</Text>
64
+ {renderHelpButton(
65
+ 'Escopo da listagem',
66
+ 'Define se este device mostra apenas os pedidos criados nele ou todos os pedidos da empresa.',
67
+ )}
68
+ </View>
69
+
70
+ {renderOptionButtons({
71
+ options: [
72
+ {
73
+ label: 'Somente deste device',
74
+ value: DEVICE_ORDER_VISIBILITY_DEVICE,
75
+ },
76
+ {
77
+ label: 'Todos da empresa',
78
+ value: DEVICE_ORDER_VISIBILITY_COMPANY,
79
+ },
80
+ ],
81
+ value: orderVisibility,
82
+ optionColors: {
83
+ buttonBackground: themeColors.buttonBackground,
84
+ buttonBorder: themeColors.buttonBorder,
85
+ buttonText: themeColors.buttonText,
86
+ buttonBackgroundSecondary: themeColors.buttonBackgroundSecondary,
87
+ buttonBorderSecondary: themeColors.buttonBorderSecondary,
88
+ buttonTextSecondary: themeColors.buttonTextSecondary,
89
+ },
90
+ onChange: value => {
91
+ const nextValue = value || DEVICE_ORDER_VISIBILITY_DEVICE;
92
+ setOrderVisibility(nextValue);
93
+ saveDeviceOrderVisibility({deviceOrderVisibility: nextValue});
94
+ },
95
+ })}
96
+ </View>
97
+
98
+ <View style={styles.configCard}>
99
+ <View style={styles.sectionTitleRow}>
100
+ <Text style={styles.configTitle}>
101
+ {tt('title', 'deliveryOnDevice') || 'Delivery neste equipamento'}
102
+ </Text>
103
+ {renderHelpButton(
104
+ tt('title', 'deliveryOnDevice') || 'Delivery neste equipamento',
105
+ tt('description', 'deliveryOnDeviceDescription') ||
106
+ 'Ative quando este equipamento precisa operar pedidos com cliente, endereço e observações de entrega.',
107
+ )}
108
+ </View>
109
+
110
+ {renderSwitchRow({
111
+ disabled: savingDeliverySettings,
112
+ label: tt('label', 'deliveryEnabled') || 'Trabalhar com delivery',
113
+ value: deliveryEnabled,
114
+ valueLabel: deliveryEnabled ? 'Ativo' : 'Inativo',
115
+ onValueChange: nextValue => {
116
+ setDeliveryEnabled(nextValue);
117
+ saveDeviceDeliverySettings({deviceDeliveryEnabled: nextValue});
118
+ },
119
+ })}
120
+ </View>
121
+ </View>
122
+
123
+ {isDisplayDevice && (
124
+ <View style={styles.section}>
125
+ <Text style={styles.sectionTitle}>
126
+ <Icon name="printer" size={13} /> {' '}Impressão de Preparo
127
+ </Text>
128
+
129
+ <View style={styles.configCard}>
130
+ <View style={styles.sectionTitleRow}>
131
+ <Text style={styles.configTitle}>
132
+ Display vinculado e impressora da fila
133
+ </Text>
134
+ {renderHelpButton(
135
+ 'Display vinculado e impressora da fila',
136
+ 'Este bloco é usado na impressão automática disparada pelo app DISPLAY.',
137
+ )}
138
+ </View>
139
+
140
+ <View style={styles.pickerWrap}>
141
+ <Picker
142
+ selectedValue={linkedDisplayId || ''}
143
+ mode={pickerMode}
144
+ style={styles.picker}
145
+ dropdownIconColor="#64748B"
146
+ onValueChange={value => {
147
+ const nextValue = String(value || '').trim();
148
+ setLinkedDisplayId(nextValue);
149
+ saveDisplayPrintingConfig({linkedDisplayId: nextValue});
150
+ }}>
151
+ <Picker.Item label="Nenhum display vinculado" value="" />
152
+ {(displayOptions || []).map(option => {
153
+ const optionId = normalizeEntityId(option);
154
+ return (
155
+ <Picker.Item
156
+ key={`display-option-${optionId}`}
157
+ label={getDisplayLabel(option)}
158
+ value={optionId}
159
+ />
160
+ );
161
+ })}
162
+ </Picker>
163
+ </View>
164
+
165
+ <View style={styles.pickerWrap}>
166
+ <Picker
167
+ selectedValue=""
168
+ mode={pickerMode}
169
+ style={styles.picker}
170
+ dropdownIconColor="#64748B"
171
+ onValueChange={() => {}}>
172
+ <Picker.Item label="Nenhuma impressora configurada" value="" />
173
+ {(printerOptions || []).map(option => {
174
+ const printerId = normalizeDeviceId(option?.device || option);
175
+ return (
176
+ <Picker.Item
177
+ key={`printer-option-${printerId}`}
178
+ label={printerLabel(option)}
179
+ value={printerId}
180
+ />
181
+ );
182
+ })}
183
+ </Picker>
184
+ </View>
185
+
186
+ {renderSwitchRow({
187
+ disabled: savingDisplayPrinting,
188
+ label: 'Pode trocar de impressora?',
189
+ value: displayAllowPrinterChange,
190
+ valueLabel: displayAllowPrinterChange ? 'Sim' : 'Nao',
191
+ onValueChange: nextValue => {
192
+ setDisplayAllowPrinterChange(nextValue);
193
+ saveDisplayPrintingConfig({
194
+ displayAllowPrinterChange: nextValue,
195
+ });
196
+ },
197
+ })}
198
+
199
+ {renderSwitchRow({
200
+ disabled: savingDisplayPrinting,
201
+ label: 'Imprimir produtos automaticamente',
202
+ value: displayAutoPrintProduct,
203
+ valueLabel: displayAutoPrintProduct ? 'Ativo' : 'Inativo',
204
+ onValueChange: nextValue => {
205
+ setDisplayAutoPrintProduct(nextValue);
206
+ saveDisplayPrintingConfig({
207
+ displayAutoPrintProductEnabled: nextValue,
208
+ });
209
+ },
210
+ })}
211
+ </View>
212
+ </View>
213
+ )}
214
+ </>
215
+ );
216
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { Text, View } from 'react-native';
3
+ import Icon from 'react-native-vector-icons/Feather';
4
+ import PaymentTypesByWalletTab from '@controleonline/ui-common/src/react/pages/SettingsPage/PaymentTypesByWalletTab';
5
+ import styles from '../../DeviceDetailPage.styles';
6
+
7
+ /**
8
+ * PDV payment types tab.
9
+ * Refs: app-community#382
10
+ */
11
+ export default function DeviceDetailPaymentSection(ctx) {
12
+ const {
13
+ showPdvPaymentTypesTab, renderHelpButton, deviceId, savePaymentTypeConfigs, savingPaymentTypes,
14
+ } = ctx;
15
+
16
+ if (!showPdvPaymentTypesTab) return null;
17
+
18
+ return (
19
+ <View style={styles.section}>
20
+ <View style={styles.sectionHeaderRow}>
21
+ <Text style={styles.sectionTitle}>
22
+ <Icon name="credit-card" size={13} /> {' '}Pagamentos do device
23
+ </Text>
24
+ {renderHelpButton(
25
+ 'Pagamentos do device',
26
+ 'Selecione os meios de pagamento que este device pode exibir e usar nas opções de pagamento. Os wallets entram só para organizar a lista.',
27
+ )}
28
+ </View>
29
+ <PaymentTypesByWalletTab
30
+ currentCompanyId={currentCompany?.id}
31
+ configs={configs}
32
+ disableSelection={savingPaymentTypes}
33
+ isSaving={savingPaymentTypes}
34
+ onPersistSelectedPaymentTypeIds={savePaymentTypeConfigs}
35
+ />
36
+ </View>
37
+ )}
38
+
39
+ );
40
+ }
@@ -0,0 +1,390 @@
1
+ import React from 'react';
2
+ import { Text, View, Switch, TextInput, TouchableOpacity, Platform } from 'react-native';
3
+ import { Picker } from '@react-native-picker/picker';
4
+ import Icon from 'react-native-vector-icons/Feather';
5
+ import styles from '../../DeviceDetailPage.styles';
6
+ import {
7
+ POS_OPERATION_MODE_OPTIONS,
8
+ POS_OPERATION_MODE_COUNTER,
9
+ POS_PRINT_MODE_ORDER,
10
+ POS_PRINT_MODE_FORM,
11
+ POS_CHECK_ORDER_TYPE_NONE,
12
+ POS_CHECK_ORDER_TYPE_TAB,
13
+ POS_CHECK_ORDER_TYPE_TABLE,
14
+ POS_CHECK_ORDER_TYPE_STAMP,
15
+ POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE,
16
+ POS_CHECK_ORDER_MANAGEMENT_MODE_EXISTING_ONLY,
17
+ POS_CASH_MANAGEMENT_MODE_CASH_REGISTER,
18
+ POS_CASH_MANAGEMENT_MODE_DAILY,
19
+ POS_OPERATION_MODE_CONFIG_KEY,
20
+ DEVICE_ORDER_VISIBILITY_COMPANY,
21
+ DEVICE_ORDER_VISIBILITY_DEVICE,
22
+ resolvePosOperationMode,
23
+ } from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
24
+ import { normalizeEntityId } from '@controleonline/ui-common/src/react/utils/paymentDevices';
25
+ import { getProductShowcaseLabel } from './deviceDetailHelpers';
26
+ import { tt } from './deviceDetailConstants';
27
+
28
+ /**
29
+ * Extracted from DeviceDetailScreen for modularization (≤500 lines).
30
+ * Refs: app-community#382
31
+ */
32
+ export default function DeviceDetailPdvConfigSection(ctx) {
33
+ const {
34
+ themeColors, brandColors, palette,
35
+ renderHelpButton, renderOptionButtons, renderSwitchRow, renderProduct,
36
+ posOperationMode, setPosOperationMode, savePosOperationMode, savingPosOperationMode,
37
+ productShowcaseId, setProductShowcaseId, saveProductShowcaseConfig,
38
+ productShowcases, loadingProductShowcases, savingProductShowcase, pickerMode,
39
+ counterAutoPrintEnabled, setCounterAutoPrintEnabled,
40
+ counterPrintMode, setCounterPrintMode,
41
+ checkOrderType, setCheckOrderType,
42
+ checkOrderManagementMode, setCheckOrderManagementMode,
43
+ cashManagementMode, setCashManagementMode,
44
+ counterCashManagementMode, setCounterCashManagementMode,
45
+ androidKioskEnabled, setAndroidKioskEnabled,
46
+ androidLauncherEnabled, setAndroidLauncherEnabled,
47
+ saveLauncherMode, savingLauncherMode,
48
+ orderVisibility, setOrderVisibility, saveDeviceOrderVisibility, savingOrderVisibility,
49
+ shouldShowOrderVisibility,
50
+ deliveryEnabled, setDeliveryEnabled, saveDeviceDeliverySettings, savingDeliverySettings,
51
+ deviceAlertSoundEnabled, setDeviceAlertSoundEnabled, deviceAlertSoundUrl, setDeviceAlertSoundUrl,
52
+ saveDeviceAlertSoundConfig, savingAlertSound,
53
+ runtimeDebugInfoEnabled, setRuntimeDebugInfoEnabled, saveDeviceRuntimeDebugInfo, savingRuntimeDebugInfo,
54
+ devicePaymentTarget, setDevicePaymentTarget, saveDevicePaymentTarget, savingPaymentTarget,
55
+ paymentDeviceOptions, displayOptions, printerOptions,
56
+ pdvGateway, setPdvGateway, pdvPrinterEnabled, setPdvPrinterEnabled, savePdvSettings, savingPdvSettings,
57
+ hasLocalPaymentGateway, loyaltyCouponsEnabled,
58
+ sendCatalogRefreshCommand, sendingCatalogRefresh,
59
+ displayAutoPrintProduct, setDisplayAutoPrintProduct,
60
+ displayAllowPrinterChange, setDisplayAllowPrinterChange,
61
+ saveDisplayPrintingConfig, savingDisplayPrinting,
62
+ linkedDisplayId, setLinkedDisplayId,
63
+ isDisplayDevice, isPdvDevice,
64
+ styles: _styles,
65
+ } = ctx;
66
+
67
+ return (
68
+ <>
69
+ <View style={styles.section}>
70
+ <Text style={styles.sectionTitle}>
71
+ <Icon name="credit-card" size={13} /> {' '}Configuração do PDV
72
+ </Text>
73
+
74
+ <View style={styles.configCard}>
75
+ <View style={styles.sectionTitleRow}>
76
+ <Text style={styles.configTitle}>
77
+ {tt('title', 'posOperationMode')}
78
+ </Text>
79
+ {renderHelpButton(
80
+ tt('title', 'posOperationMode') || 'Modo de operacao',
81
+ tt('description', 'posOperationModeDescription') ||
82
+ 'Escolha o modo, a trava kiosk e a politica de ordem/caixa deste device.',
83
+ )}
84
+ </View>
85
+
86
+ {renderOptionButtons({
87
+ options: POS_OPERATION_MODE_OPTIONS.map(option => ({
88
+ label: tt('option', option.translationKey),
89
+ value: option.value,
90
+ })),
91
+ value: posOperationMode,
92
+ optionColors: {
93
+ buttonBackground: themeColors.buttonBackground,
94
+ buttonBorder: themeColors.buttonBorder,
95
+ buttonText: themeColors.buttonText,
96
+ buttonBackgroundSecondary: themeColors.buttonBackgroundSecondary,
97
+ buttonBorderSecondary: themeColors.buttonBorderSecondary,
98
+ buttonTextSecondary: themeColors.buttonTextSecondary,
99
+ },
100
+ onChange: value => {
101
+ const nextValue = resolvePosOperationMode({
102
+ [POS_OPERATION_MODE_CONFIG_KEY]: value,
103
+ });
104
+ setPosOperationMode(nextValue);
105
+ savePosOperationMode({posOperationMode: nextValue});
106
+ },
107
+ })}
108
+
109
+ <View style={styles.pickerWrap}>
110
+ <Picker
111
+ selectedValue={productShowcaseId || ''}
112
+ mode={pickerMode}
113
+ enabled={!loadingProductShowcases && !savingProductShowcase}
114
+ style={styles.picker}
115
+ dropdownIconColor="#64748B"
116
+ onValueChange={value => {
117
+ const nextValue = normalizeEntityId(value);
118
+ setProductShowcaseId(nextValue);
119
+ saveProductShowcaseConfig({productShowcaseId: nextValue});
120
+ }}>
121
+ <Picker.Item
122
+ label={
123
+ loadingProductShowcases
124
+ ? 'Carregando vitrines...'
125
+ : 'Sem vitrine vinculada'
126
+ }
127
+ value=""
128
+ />
129
+ {productShowcases.map(showcase => {
130
+ const showcaseId = normalizeEntityId(showcase);
131
+ return (
132
+ <Picker.Item
133
+ key={`pos-showcase-${showcaseId}`}
134
+ label={getProductShowcaseLabel(showcase)}
135
+ value={showcaseId}
136
+ />
137
+ );
138
+ })}
139
+ </Picker>
140
+ </View>
141
+
142
+ {renderSwitchRow({
143
+ disabled: savingPosOperationMode,
144
+ label: 'Modo Kiosk',
145
+ value: androidKioskEnabled,
146
+ valueLabel: androidKioskEnabled ? 'Ativo' : 'Inativo',
147
+ onValueChange: nextValue => {
148
+ setAndroidKioskEnabled(nextValue);
149
+ savePosOperationMode({androidKioskEnabled: nextValue});
150
+ },
151
+ })}
152
+
153
+ {renderOptionButtons({
154
+ options: [
155
+ {
156
+ label: global.t?.t('configs', 'option', 'none') || 'None',
157
+ value: POS_CHECK_ORDER_TYPE_NONE,
158
+ },
159
+ {
160
+ label: global.t?.t('orders', 'title', 'tab') || 'Tab',
161
+ value: POS_CHECK_ORDER_TYPE_TAB,
162
+ },
163
+ {
164
+ label: global.t?.t('orders', 'title', 'table') || 'Table',
165
+ value: POS_CHECK_ORDER_TYPE_TABLE,
166
+ },
167
+ {
168
+ label: global.t?.t('orders', 'title', 'stamp') || 'Stamp',
169
+ value: POS_CHECK_ORDER_TYPE_STAMP,
170
+ disabled: !loyaltyCouponsEnabled,
171
+ title: !loyaltyCouponsEnabled
172
+ ? 'Ative em Shop -> Cupom fidelidade\npara liberar Stamp'
173
+ : '',
174
+ },
175
+ ],
176
+ value: checkOrderType,
177
+ optionColors: {
178
+ buttonBackground: themeColors.buttonBackground,
179
+ buttonBorder: themeColors.buttonBorder,
180
+ buttonText: themeColors.buttonText,
181
+ buttonBackgroundSecondary: themeColors.buttonBackgroundSecondary,
182
+ buttonBorderSecondary: themeColors.buttonBorderSecondary,
183
+ buttonTextSecondary: themeColors.buttonTextSecondary,
184
+ },
185
+ onChange: value => {
186
+ const nextCheckOrderType =
187
+ value === POS_CHECK_ORDER_TYPE_TAB
188
+ ? POS_CHECK_ORDER_TYPE_TAB
189
+ : value === POS_CHECK_ORDER_TYPE_TABLE
190
+ ? POS_CHECK_ORDER_TYPE_TABLE
191
+ : value === POS_CHECK_ORDER_TYPE_STAMP
192
+ ? loyaltyCouponsEnabled
193
+ ? POS_CHECK_ORDER_TYPE_STAMP
194
+ : POS_CHECK_ORDER_TYPE_NONE
195
+ : POS_CHECK_ORDER_TYPE_NONE;
196
+ const nextCheckOrderManagementMode =
197
+ nextCheckOrderType === POS_CHECK_ORDER_TYPE_NONE
198
+ ? POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE
199
+ : checkOrderManagementMode;
200
+ setCheckOrderType(nextCheckOrderType);
201
+ if (nextCheckOrderType === POS_CHECK_ORDER_TYPE_NONE) {
202
+ setCheckOrderManagementMode(
203
+ POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE,
204
+ );
205
+ }
206
+ savePosOperationMode({
207
+ checkOrderType: nextCheckOrderType,
208
+ checkOrderManagementMode: nextCheckOrderManagementMode,
209
+ });
210
+ },
211
+ })}
212
+
213
+ {checkOrderType !== POS_CHECK_ORDER_TYPE_NONE &&
214
+ renderOptionButtons({
215
+ options: [
216
+ {
217
+ label:
218
+ global.t?.t(
219
+ 'configs',
220
+ 'option',
221
+ 'manageLinkedOrders',
222
+ ) || 'Open and close tabs/tables/stamps',
223
+ value: POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE,
224
+ },
225
+ {
226
+ label:
227
+ global.t?.t(
228
+ 'configs',
229
+ 'option',
230
+ 'existingLinkedOrdersOnly',
231
+ ) || 'Use open tabs/tables/stamps only',
232
+ value: POS_CHECK_ORDER_MANAGEMENT_MODE_EXISTING_ONLY,
233
+ },
234
+ ],
235
+ value: checkOrderManagementMode,
236
+ onChange: value => {
237
+ const nextValue =
238
+ value === POS_CHECK_ORDER_MANAGEMENT_MODE_EXISTING_ONLY
239
+ ? POS_CHECK_ORDER_MANAGEMENT_MODE_EXISTING_ONLY
240
+ : POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE;
241
+ setCheckOrderManagementMode(nextValue);
242
+ savePosOperationMode({checkOrderManagementMode: nextValue});
243
+ },
244
+ })}
245
+
246
+ {posOperationMode === POS_OPERATION_MODE_COUNTER && (
247
+ <>
248
+ {renderSwitchRow({
249
+ disabled: savingPosOperationMode,
250
+ label: 'Impressao automatica',
251
+ value: counterAutoPrintEnabled,
252
+ valueLabel: counterAutoPrintEnabled ? 'Sim' : 'Nao',
253
+ onValueChange: nextValue => {
254
+ setCounterAutoPrintEnabled(nextValue);
255
+ savePosOperationMode({counterAutoPrintEnabled: nextValue});
256
+ },
257
+ })}
258
+
259
+ {counterAutoPrintEnabled &&
260
+ renderOptionButtons({
261
+ options: [
262
+ {label: 'Pedido', value: POS_PRINT_MODE_ORDER},
263
+ {label: 'Fichas', value: POS_PRINT_MODE_FORM},
264
+ ],
265
+ value: counterPrintMode,
266
+ optionColors: {
267
+ buttonBackground: themeColors.buttonBackground,
268
+ buttonBorder: themeColors.buttonBorder,
269
+ buttonText: themeColors.buttonText,
270
+ buttonBackgroundSecondary: themeColors.buttonBackgroundSecondary,
271
+ buttonBorderSecondary: themeColors.buttonBorderSecondary,
272
+ buttonTextSecondary: themeColors.buttonTextSecondary,
273
+ },
274
+ onChange: value => {
275
+ const nextValue =
276
+ value === POS_PRINT_MODE_FORM
277
+ ? POS_PRINT_MODE_FORM
278
+ : POS_PRINT_MODE_ORDER;
279
+ setCounterPrintMode(nextValue);
280
+ savePosOperationMode({counterPrintMode: nextValue});
281
+ },
282
+ })}
283
+
284
+ {renderOptionButtons({
285
+ options: [
286
+ {
287
+ label: 'Abertura e fechamento de caixa',
288
+ value: POS_CASH_MANAGEMENT_MODE_CASH_REGISTER,
289
+ },
290
+ {
291
+ label: 'Fechamento diario',
292
+ value: POS_CASH_MANAGEMENT_MODE_DAILY,
293
+ },
294
+ ],
295
+ value: counterCashManagementMode,
296
+ optionColors: {
297
+ buttonBackground: themeColors.buttonBackground,
298
+ buttonBorder: themeColors.buttonBorder,
299
+ buttonText: themeColors.buttonText,
300
+ buttonBackgroundSecondary: themeColors.buttonBackgroundSecondary,
301
+ buttonBorderSecondary: themeColors.buttonBorderSecondary,
302
+ buttonTextSecondary: themeColors.buttonTextSecondary,
303
+ },
304
+ onChange: value => {
305
+ const nextValue =
306
+ value === POS_CASH_MANAGEMENT_MODE_DAILY
307
+ ? POS_CASH_MANAGEMENT_MODE_DAILY
308
+ : POS_CASH_MANAGEMENT_MODE_CASH_REGISTER;
309
+ setCounterCashManagementMode(nextValue);
310
+ savePosOperationMode({counterCashManagementMode: nextValue});
311
+ },
312
+ })}
313
+ </>
314
+ )}
315
+ </View>
316
+
317
+ <View style={styles.configCard}>
318
+ <View style={styles.sectionTitleRow}>
319
+ <Text style={[styles.configTitle, {color: brandColors.text}]}>
320
+ {tt('title', 'androidLauncherMode') || 'Launcher / home app'}
321
+ </Text>
322
+ {renderHelpButton(
323
+ tt('title', 'androidLauncherMode') || 'Launcher / home app',
324
+ tt('description', 'androidLauncherDescription') ||
325
+ 'Quando ativado, o device volta para a app ao usar home ou apps recentes. O voltar continua seguindo a tela.',
326
+ )}
327
+ </View>
328
+
329
+ {renderSwitchRow({
330
+ disabled: savingLauncherMode,
331
+ label: 'Modo launcher?',
332
+ value: androidLauncherEnabled,
333
+ valueLabel: androidLauncherEnabled ? 'Ativo' : 'Inativo',
334
+ onValueChange: nextValue => {
335
+ setAndroidLauncherEnabled(nextValue);
336
+ saveLauncherMode({androidLauncherEnabled: nextValue});
337
+ },
338
+ })}
339
+ <Text style={[styles.deviceString, {color: brandColors.textSecondary}]}>
340
+ Salva automaticamente
341
+ </Text>
342
+ </View>
343
+
344
+ <View style={styles.configCard}>
345
+ <View style={styles.sectionTitleRow}>
346
+ <Text style={styles.configTitle}>Gateway e impressora</Text>
347
+ {renderHelpButton(
348
+ 'Gateway e impressora',
349
+ 'Escolha o gateway usado pelo PDV e se ele pode aparecer como destino de impressao.',
350
+ )}
351
+ </View>
352
+
353
+ {renderOptionButtons({
354
+ options: [
355
+ {label: 'Nenhum', value: ''},
356
+ {label: 'Infinite Pay', value: 'infinite-pay'},
357
+ {label: 'Cielo', value: 'cielo'},
358
+ ],
359
+ value: pdvGateway || '',
360
+ optionColors: {
361
+ buttonBackground: themeColors.buttonBackground,
362
+ buttonBorder: themeColors.buttonBorder,
363
+ buttonText: themeColors.buttonText,
364
+ buttonBackgroundSecondary: themeColors.buttonBackgroundSecondary,
365
+ buttonBorderSecondary: themeColors.buttonBorderSecondary,
366
+ buttonTextSecondary: themeColors.buttonTextSecondary,
367
+ },
368
+ onChange: value => {
369
+ const nextValue = String(value || '');
370
+ setPdvGateway(nextValue);
371
+ savePdvSettings({pdvGateway: nextValue});
372
+ },
373
+ })}
374
+
375
+ {renderSwitchRow({
376
+ disabled: savingPdvSettings,
377
+ label: 'Impressora',
378
+ value: pdvPrinterEnabled,
379
+ valueLabel: pdvPrinterEnabled ? 'Sim' : 'Nao',
380
+ onValueChange: nextValue => {
381
+ setPdvPrinterEnabled(nextValue);
382
+ savePdvSettings({pdvPrinterEnabled: nextValue});
383
+ },
384
+ })}
385
+ <Text style={styles.deviceString}>Salva automaticamente</Text>
386
+ </View>
387
+ </View>
388
+ </>
389
+ );
390
+ }