@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.
Files changed (203) hide show
  1. package/.github/agents/developer.agent.md +30 -0
  2. package/.github/agents/devops.agent.md +30 -0
  3. package/.github/agents/qa.agent.md +30 -0
  4. package/.github/agents/security.agent.md +30 -0
  5. package/.github/workflows/npmjs.yml +35 -0
  6. package/.github/workflows/pull-request-checks.yml +19 -0
  7. package/.scrutinizer.yml +24 -0
  8. package/FUNDING.yml +1 -0
  9. package/package.json +28 -0
  10. package/src/api/fetch.js +74 -0
  11. package/src/api/index.js +155 -0
  12. package/src/api/localDB.js +131 -0
  13. package/src/api/queue.js +66 -0
  14. package/src/react/assets/tap.mp3 +0 -0
  15. package/src/react/components/AddImportModal.js +157 -0
  16. package/src/react/components/AddImportModal.styles.js +81 -0
  17. package/src/react/components/BackgroundRuntimeBridge.js +219 -0
  18. package/src/react/components/BottomNavigationBar.config.js +238 -0
  19. package/src/react/components/BottomNavigationBar.js +120 -0
  20. package/src/react/components/BottomNavigationBar.styles.js +110 -0
  21. package/src/react/components/CategoryForm.js +572 -0
  22. package/src/react/components/CategoryForm.styles.js +334 -0
  23. package/src/react/components/ConfirmModal.js +24 -0
  24. package/src/react/components/ConfirmModal.styles.js +43 -0
  25. package/src/react/components/ContextHelpButton.js +69 -0
  26. package/src/react/components/ContextHelpButton.styles.js +62 -0
  27. package/src/react/components/DefaultProvider.native.js +848 -0
  28. package/src/react/components/DefaultProvider.styles.js +21 -0
  29. package/src/react/components/DefaultProvider.web.js +909 -0
  30. package/src/react/components/DeliveryPushBridge.native.js +314 -0
  31. package/src/react/components/DeliveryPushBridge.web.js +5 -0
  32. package/src/react/components/DeviceAlertSoundService.js +499 -0
  33. package/src/react/components/EntityLogContent.js +909 -0
  34. package/src/react/components/EntityLogContent.styles.js +400 -0
  35. package/src/react/components/EventBus.js +12 -0
  36. package/src/react/components/KioskModeBridge.js +65 -0
  37. package/src/react/components/LauncherModeBridge.js +47 -0
  38. package/src/react/components/LinkedOrderProductsTab.js +388 -0
  39. package/src/react/components/LinkedOrderProductsTab.styles.js +180 -0
  40. package/src/react/components/ManagerPushBridge.native.js +345 -0
  41. package/src/react/components/MessageService.js +314 -0
  42. package/src/react/components/Paywall/Google.js +89 -0
  43. package/src/react/components/PrintService.js +778 -0
  44. package/src/react/components/ProductCatalogCacheService.js +45 -0
  45. package/src/react/components/RemoteCheckoutService.js +292 -0
  46. package/src/react/components/RuntimeBottomNavigationBar.js +151 -0
  47. package/src/react/components/RuntimeInfoFooter.js +214 -0
  48. package/src/react/components/RuntimeInfoFooter.styles.js +56 -0
  49. package/src/react/components/SystemErrorToast.js +29 -0
  50. package/src/react/components/SystemErrorToast.styles.js +38 -0
  51. package/src/react/components/TouchFeedbackProvider.js +65 -0
  52. package/src/react/components/UnifiedPaymentBar.js +155 -0
  53. package/src/react/components/UnifiedPaymentBar.styles.js +174 -0
  54. package/src/react/components/WebsocketListener.native.js +487 -0
  55. package/src/react/components/WebsocketListener.web.js +102 -0
  56. package/src/react/components/inputs/IdInput.js +49 -0
  57. package/src/react/components/inputs/IdInput.styles.js +26 -0
  58. package/src/react/components/inputs/InvoiceDueDateFilterInput.js +74 -0
  59. package/src/react/components/inputs/InvoiceDueDateFilterInput.styles.js +34 -0
  60. package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.js +115 -0
  61. package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.styles.js +39 -0
  62. package/src/react/components/lists/CategoriesList.js +56 -0
  63. package/src/react/components/lists/PaymentTypeList.js +55 -0
  64. package/src/react/components/lists/ReceiverList.js +56 -0
  65. package/src/react/components/lists/SelectList.styles.js +18 -0
  66. package/src/react/components/lists/StatusList.js +55 -0
  67. package/src/react/components/lists/WalletList.js +54 -0
  68. package/src/react/components/radio/Spotify.js +144 -0
  69. package/src/react/components/radio/Spotify.styles.js +32 -0
  70. package/src/react/components/radio/YouTube.js +82 -0
  71. package/src/react/components/radio/YouTube.styles.js +16 -0
  72. package/src/react/components/toastConfig.js +16 -0
  73. package/src/react/config/deviceConfigBootstrap.js +571 -0
  74. package/src/react/index.js +4 -0
  75. package/src/react/localStorage.js +30 -0
  76. package/src/react/pages/EntityLogPage.js +124 -0
  77. package/src/react/pages/EntityLogPage.styles.js +17 -0
  78. package/src/react/pages/GenericLogPage.js +760 -0
  79. package/src/react/pages/GenericLogPage.styles.js +401 -0
  80. package/src/react/pages/Imports.js +361 -0
  81. package/src/react/pages/Imports.styles.js +223 -0
  82. package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +462 -0
  83. package/src/react/pages/SettingsPage/index.js +1171 -0
  84. package/src/react/pages/SettingsPage/index.styles.js +122 -0
  85. package/src/react/print/jobs.js +147 -0
  86. package/src/react/print/providers/local.js +53 -0
  87. package/src/react/print/providers/remote.js +81 -0
  88. package/src/react/print/selection.js +296 -0
  89. package/src/react/print/usePrintButtonController.js +474 -0
  90. package/src/react/router/routes.js +42 -0
  91. package/src/react/services/NetworkPrinterService.native.js +391 -0
  92. package/src/react/services/NetworkPrinterService.web.js +15 -0
  93. package/src/react/stores/index.js +128 -0
  94. package/src/react/stores/storeErrorBridge.js +36 -0
  95. package/src/react/utils/backgroundRuntimeRegistration.js +69 -0
  96. package/src/react/utils/cashPayment.js +87 -0
  97. package/src/react/utils/commercialDocumentOrders.js +269 -0
  98. package/src/react/utils/dateRangeFilter.js +264 -0
  99. package/src/react/utils/deviceRuntime.js +193 -0
  100. package/src/react/utils/entityDisplay.js +231 -0
  101. package/src/react/utils/entityLog.js +649 -0
  102. package/src/react/utils/fileUrl.js +102 -0
  103. package/src/react/utils/frontendDebugLog.js +45 -0
  104. package/src/react/utils/googleMapsConfig.js +49 -0
  105. package/src/react/utils/importStatus.js +100 -0
  106. package/src/react/utils/invoiceDueDateMessages.js +14 -0
  107. package/src/react/utils/invoicePresentation.js +46 -0
  108. package/src/react/utils/logSettings.js +143 -0
  109. package/src/react/utils/maintenanceSettings.js +53 -0
  110. package/src/react/utils/managerOrderNotifications.js +523 -0
  111. package/src/react/utils/mapNavigation.js +76 -0
  112. package/src/react/utils/menuCatalogConfig.js +8 -0
  113. package/src/react/utils/menuCatalogDownload.js +157 -0
  114. package/src/react/utils/networkCameraDevices.js +175 -0
  115. package/src/react/utils/networkDeviceProfiles.js +135 -0
  116. package/src/react/utils/normalizedCatalogDownload.js +157 -0
  117. package/src/react/utils/notificationNavigation.js +94 -0
  118. package/src/react/utils/notificationSound.js +42 -0
  119. package/src/react/utils/paymentDevices.js +397 -0
  120. package/src/react/utils/paymentGatewayExecution.js +91 -0
  121. package/src/react/utils/paymentOptions.js +88 -0
  122. package/src/react/utils/peopleDisplay.js +39 -0
  123. package/src/react/utils/printerDevices.js +465 -0
  124. package/src/react/utils/remotePayment.js +61 -0
  125. package/src/react/utils/runtimeFooter.js +475 -0
  126. package/src/react/utils/runtimeLanguage.js +50 -0
  127. package/src/react/utils/runtimeMenu.js +224 -0
  128. package/src/react/utils/screenMetrics.js +30 -0
  129. package/src/react/utils/shopConfig.js +294 -0
  130. package/src/react/utils/shopFranchises.js +114 -0
  131. package/src/react/utils/socketRuntimePipeline.js +454 -0
  132. package/src/react/utils/spoolAckTracker.js +77 -0
  133. package/src/react/utils/storeColumns.js +427 -0
  134. package/src/react/utils/systemErrorChannel.js +109 -0
  135. package/src/react/utils/systemErrorMessage.js +67 -0
  136. package/src/react/utils/toastPresentation.js +53 -0
  137. package/src/react/utils/websocketSharedRuntime.js +826 -0
  138. package/src/store/acl/getters.js +4 -0
  139. package/src/store/acl/index.js +19 -0
  140. package/src/store/acl/mutation_types.js +4 -0
  141. package/src/store/acl/mutations.js +17 -0
  142. package/src/store/address/city.js +22 -0
  143. package/src/store/categories/category_file/index.js +25 -0
  144. package/src/store/categories/index.js +93 -0
  145. package/src/store/configs/customActions.js +131 -0
  146. package/src/store/configs/index.js +25 -0
  147. package/src/store/connections/customActions.js +26 -0
  148. package/src/store/connections/index.js +124 -0
  149. package/src/store/device/index.js +22 -0
  150. package/src/store/device_config/customActions.js +190 -0
  151. package/src/store/device_config/index.js +28 -0
  152. package/src/store/entity_log/customActions.js +63 -0
  153. package/src/store/entity_log/index.js +25 -0
  154. package/src/store/extra/data.js +85 -0
  155. package/src/store/extra/fields.js +88 -0
  156. package/src/store/file/actions.js +27 -0
  157. package/src/store/file/index.js +24 -0
  158. package/src/store/imports/index.js +88 -0
  159. package/src/store/print/customActions.js +251 -0
  160. package/src/store/print/index.js +28 -0
  161. package/src/store/printer/customActions.js +54 -0
  162. package/src/store/printer/index.js +26 -0
  163. package/src/store/runtime_debug/customActions.js +71 -0
  164. package/src/store/runtime_debug/index.js +30 -0
  165. package/src/store/status/index.js +65 -0
  166. package/src/store/timezones/index.js +43 -0
  167. package/src/store/websocket/customActions.js +24 -0
  168. package/src/store/websocket/index.js +28 -0
  169. package/src/tests/react/components/LauncherModeBridge.test.js +93 -0
  170. package/src/tests/react/config/deviceConfigBootstrap.test.js +337 -0
  171. package/src/tests/react/print/localPrintProvider.test.js +45 -0
  172. package/src/tests/react/utils/backgroundRuntimeRegistration.test.js +123 -0
  173. package/src/tests/react/utils/cashPayment.test.js +41 -0
  174. package/src/tests/react/utils/dateRangeFilter.test.mjs +29 -0
  175. package/src/tests/react/utils/entityDisplay.test.js +18 -0
  176. package/src/tests/react/utils/googleMapsConfig.test.js +32 -0
  177. package/src/tests/react/utils/importStatus.test.js +85 -0
  178. package/src/tests/react/utils/invoicePresentation.test.mjs +40 -0
  179. package/src/tests/react/utils/managerOrderNotifications.test.js +127 -0
  180. package/src/tests/react/utils/mapNavigation.test.js +58 -0
  181. package/src/tests/react/utils/notificationNavigation.test.js +39 -0
  182. package/src/tests/react/utils/notificationSound.test.js +27 -0
  183. package/src/tests/react/utils/paymentDevices.test.js +88 -0
  184. package/src/tests/react/utils/runtimeFooter.test.js +429 -0
  185. package/src/tests/react/utils/runtimeLanguage.test.js +80 -0
  186. package/src/tests/react/utils/runtimeMenu.test.js +174 -0
  187. package/src/tests/react/utils/shopFranchises.test.js +82 -0
  188. package/src/tests/react/utils/socketRuntimePipeline.test.js +124 -0
  189. package/src/tests/react/utils/spoolAckTracker.test.js +40 -0
  190. package/src/tests/react/utils/storeErrorBridge.test.js +66 -0
  191. package/src/tests/react/utils/systemErrorChannel.test.js +58 -0
  192. package/src/tests/react/utils/systemErrorMessage.test.js +59 -0
  193. package/src/tests/react/utils/toastPresentation.test.js +75 -0
  194. package/src/tests/react/utils/translate.test.mjs +396 -0
  195. package/src/tests/react/utils/websocketSharedRuntime.test.js +245 -0
  196. package/src/utils/apiEntryPoint.js +31 -0
  197. package/src/utils/appDomain.js +50 -0
  198. package/src/utils/config.js +14 -0
  199. package/src/utils/formatter.js +419 -0
  200. package/src/utils/integrationConfigs.js +79 -0
  201. package/src/utils/methods.js +23 -0
  202. package/src/utils/oauth.js +42 -0
  203. package/src/utils/translate.js +620 -0
@@ -0,0 +1,462 @@
1
+ import React, {useCallback, useEffect, useMemo, useState} from 'react';
2
+ import {
3
+ Alert,
4
+ StyleSheet,
5
+ Text,
6
+ TouchableOpacity,
7
+ View,
8
+ } from 'react-native';
9
+
10
+ import {useStore} from '@store';
11
+ import StateStore from '@controleonline/ui-layout/src/react/components/StateStore';
12
+ import DefaultTooltip from '@controleonline/ui-default/src/react/components/help/DefaultTooltip';
13
+ import {
14
+ groupWalletPaymentTypesByWalletId,
15
+ normalizeEntityId,
16
+ resolveDevicePaymentTypeIds,
17
+ } from '@controleonline/ui-common/src/react/utils/paymentDevices';
18
+
19
+ const resolveWalletLabel = wallet => {
20
+ return String(wallet?.wallet ?? '').trim();
21
+ };
22
+
23
+ const resolvePaymentTypeLabel = walletPaymentType => {
24
+ const paymentType = walletPaymentType?.paymentType;
25
+
26
+ if (!paymentType || typeof paymentType !== 'object') {
27
+ return '';
28
+ }
29
+
30
+ return String(paymentType.paymentType ?? '').trim();
31
+ };
32
+
33
+ const localStyles = StyleSheet.create({
34
+ container: {
35
+ marginTop: 16,
36
+ paddingBottom: 8,
37
+ },
38
+ introCard: {
39
+ backgroundColor: '#EFF6FF',
40
+ borderColor: '#BFDBFE',
41
+ borderRadius: 12,
42
+ borderWidth: 1,
43
+ padding: 14,
44
+ },
45
+ introHeaderRow: {
46
+ alignItems: 'center',
47
+ flexDirection: 'row',
48
+ gap: 10,
49
+ justifyContent: 'space-between',
50
+ },
51
+ introTitle: {
52
+ color: '#1E3A8A',
53
+ fontSize: 16,
54
+ fontWeight: '700',
55
+ },
56
+ emptyCard: {
57
+ backgroundColor: '#F8FAFC',
58
+ borderRadius: 12,
59
+ marginTop: 14,
60
+ padding: 14,
61
+ },
62
+ emptyTitle: {
63
+ color: '#0F172A',
64
+ fontSize: 14,
65
+ fontWeight: '700',
66
+ marginBottom: 4,
67
+ },
68
+ emptyText: {
69
+ color: '#64748B',
70
+ fontSize: 12,
71
+ lineHeight: 18,
72
+ },
73
+ walletList: {
74
+ marginTop: 12,
75
+ gap: 12,
76
+ },
77
+ walletCard: {
78
+ backgroundColor: '#FFFFFF',
79
+ borderColor: '#E2E8F0',
80
+ borderRadius: 14,
81
+ borderWidth: 1,
82
+ padding: 14,
83
+ },
84
+ walletCardHeader: {
85
+ alignItems: 'center',
86
+ flexDirection: 'row',
87
+ justifyContent: 'space-between',
88
+ },
89
+ walletMeta: {
90
+ flex: 1,
91
+ minWidth: 0,
92
+ },
93
+ walletName: {
94
+ color: '#0F172A',
95
+ fontSize: 15,
96
+ fontWeight: '700',
97
+ },
98
+ walletId: {
99
+ color: '#64748B',
100
+ fontSize: 12,
101
+ marginTop: 2,
102
+ },
103
+ paymentTypesBlock: {
104
+ marginTop: 12,
105
+ },
106
+ paymentTypesTitle: {
107
+ color: '#334155',
108
+ fontSize: 12,
109
+ fontWeight: '700',
110
+ marginBottom: 8,
111
+ },
112
+ paymentTypesRow: {
113
+ flexDirection: 'row',
114
+ flexWrap: 'wrap',
115
+ gap: 8,
116
+ },
117
+ paymentTypeChip: {
118
+ alignSelf: 'flex-start',
119
+ backgroundColor: '#E0F2FE',
120
+ borderColor: '#BAE6FD',
121
+ borderRadius: 999,
122
+ borderWidth: 1,
123
+ paddingHorizontal: 10,
124
+ paddingVertical: 8,
125
+ },
126
+ paymentTypeChipSelected: {
127
+ backgroundColor: '#1B5587',
128
+ borderColor: '#1B5587',
129
+ },
130
+ paymentTypeChipDisabled: {
131
+ opacity: 0.55,
132
+ },
133
+ paymentTypeChipText: {
134
+ color: '#0369A1',
135
+ fontSize: 12,
136
+ fontWeight: '700',
137
+ },
138
+ paymentTypeChipTextSelected: {
139
+ color: '#FFFFFF',
140
+ },
141
+ paymentTypesEmpty: {
142
+ color: '#64748B',
143
+ fontSize: 12,
144
+ lineHeight: 18,
145
+ },
146
+ footerHintRow: {
147
+ marginTop: 12,
148
+ },
149
+ footerHint: {
150
+ color: '#64748B',
151
+ fontSize: 12,
152
+ lineHeight: 18,
153
+ },
154
+ });
155
+
156
+ const PaymentTypesByWalletTab = ({
157
+ configs,
158
+ currentCompanyId,
159
+ disableSelection = false,
160
+ isSaving = false,
161
+ onPersistSelectedPaymentTypeIds,
162
+ title = 'Pagamentos',
163
+ introText = 'Os wallets organizam a lista, mas o que vale é a seleção dos meios de pagamento.',
164
+ helpText = 'Esta seleção é a fonte usada pelo runtime para mostrar os pagamentos disponíveis neste contexto.',
165
+ loadingWalletsText = 'Carregando wallets da empresa...',
166
+ loadingPaymentsText = 'Carregando meios de pagamento...',
167
+ emptyTitle = 'Nenhuma wallet encontrada',
168
+ emptyText = 'Não há wallets carregadas para a empresa ativa.',
169
+ emptyPaymentsText = 'Nenhum meio de pagamento vinculado a esta wallet.',
170
+ unassignedTitle = 'Sem carteira',
171
+ unassignedText = 'Meios de pagamento sem wallet vinculada.',
172
+ }) => {
173
+ const walletStore = useStore('wallet');
174
+ const walletPaymentTypeStore = useStore('walletPaymentType');
175
+ const {getters: walletGetters, actions: walletActions} = walletStore;
176
+ const {
177
+ getters: walletPaymentTypeGetters,
178
+ actions: walletPaymentTypeActions,
179
+ } = walletPaymentTypeStore;
180
+
181
+ const wallets = Array.isArray(walletGetters.items) ? walletGetters.items : [];
182
+ const walletPaymentTypes = Array.isArray(walletPaymentTypeGetters.items)
183
+ ? walletPaymentTypeGetters.items
184
+ : [];
185
+ const walletsLoading = walletGetters.isLoading === true;
186
+ const walletPaymentTypesLoading = walletPaymentTypeGetters.isLoading === true;
187
+ const [selectedPaymentTypeIds, setSelectedPaymentTypeIds] = useState([]);
188
+
189
+ useEffect(() => {
190
+ if (!currentCompanyId) {
191
+ walletActions.setItems([]);
192
+ walletPaymentTypeActions.setItems([]);
193
+ return;
194
+ }
195
+
196
+ walletActions
197
+ .getItems({people: currentCompanyId})
198
+ .catch(() => {
199
+ walletActions.setItems([]);
200
+ });
201
+ walletPaymentTypeActions
202
+ .getItems({'wallet.people': currentCompanyId})
203
+ .catch(() => {
204
+ walletPaymentTypeActions.setItems([]);
205
+ });
206
+ }, [currentCompanyId, walletActions, walletPaymentTypeActions]);
207
+
208
+ useEffect(() => {
209
+ const nextSelectedPaymentTypeIds = resolveDevicePaymentTypeIds(configs);
210
+ setSelectedPaymentTypeIds(current => {
211
+ const currentSignature = current
212
+ .map(normalizeEntityId)
213
+ .filter(Boolean)
214
+ .join(',');
215
+ const nextSignature = nextSelectedPaymentTypeIds
216
+ .map(normalizeEntityId)
217
+ .filter(Boolean)
218
+ .join(',');
219
+
220
+ return currentSignature === nextSignature
221
+ ? current
222
+ : nextSelectedPaymentTypeIds;
223
+ });
224
+ }, [configs]);
225
+
226
+ const selectedPaymentTypeIdSet = useMemo(
227
+ () => new Set(selectedPaymentTypeIds.map(normalizeEntityId).filter(Boolean)),
228
+ [selectedPaymentTypeIds],
229
+ );
230
+
231
+ const walletGroups = useMemo(() => {
232
+ const groupedPaymentTypes = groupWalletPaymentTypesByWalletId(
233
+ walletPaymentTypes,
234
+ );
235
+ const groupedWalletIds = new Set();
236
+
237
+ const groups = wallets
238
+ .map(wallet => {
239
+ const walletId = normalizeEntityId(wallet?.id);
240
+
241
+ if (!walletId) {
242
+ return null;
243
+ }
244
+
245
+ groupedWalletIds.add(walletId);
246
+
247
+ return {
248
+ key: walletId,
249
+ walletId,
250
+ wallet,
251
+ paymentTypes: groupedPaymentTypes[walletId] ?? [],
252
+ isUnassigned: false,
253
+ };
254
+ })
255
+ .filter(Boolean);
256
+
257
+ Object.entries(groupedPaymentTypes).forEach(([walletId, paymentTypes]) => {
258
+ if (walletId === '__unassigned' || groupedWalletIds.has(walletId)) {
259
+ return;
260
+ }
261
+
262
+ groups.push({
263
+ key: `wallet-${walletId}`,
264
+ walletId,
265
+ wallet: paymentTypes[0]?.wallet ?? null,
266
+ paymentTypes,
267
+ isUnassigned: false,
268
+ });
269
+ });
270
+
271
+ const unassignedPaymentTypes = groupedPaymentTypes.__unassigned ?? [];
272
+ if (unassignedPaymentTypes.length > 0) {
273
+ groups.push({
274
+ key: '__unassigned',
275
+ walletId: '',
276
+ wallet: null,
277
+ paymentTypes: unassignedPaymentTypes,
278
+ isUnassigned: true,
279
+ });
280
+ }
281
+
282
+ return groups;
283
+ }, [walletPaymentTypes, wallets]);
284
+
285
+ const persistSelectedPaymentTypeIds = useCallback(
286
+ nextSelectedPaymentTypeIds => {
287
+ if (typeof onPersistSelectedPaymentTypeIds !== 'function') {
288
+ return Promise.resolve(nextSelectedPaymentTypeIds);
289
+ }
290
+
291
+ return Promise.resolve(onPersistSelectedPaymentTypeIds(nextSelectedPaymentTypeIds));
292
+ },
293
+ [onPersistSelectedPaymentTypeIds],
294
+ );
295
+
296
+ const handleTogglePaymentType = useCallback(
297
+ paymentTypeId => {
298
+ const normalizedPaymentTypeId = normalizeEntityId(paymentTypeId);
299
+
300
+ if (!normalizedPaymentTypeId || isSaving || disableSelection) {
301
+ return;
302
+ }
303
+
304
+ const currentIds = [
305
+ ...new Set(
306
+ selectedPaymentTypeIds.map(normalizeEntityId).filter(Boolean),
307
+ ),
308
+ ];
309
+ const nextIdsSet = new Set(currentIds);
310
+ const wasSelected = nextIdsSet.has(normalizedPaymentTypeId);
311
+
312
+ if (wasSelected) {
313
+ nextIdsSet.delete(normalizedPaymentTypeId);
314
+ } else {
315
+ nextIdsSet.add(normalizedPaymentTypeId);
316
+ }
317
+
318
+ const nextSelectedIds = currentIds.filter(id => nextIdsSet.has(id));
319
+ if (!wasSelected) {
320
+ nextSelectedIds.push(normalizedPaymentTypeId);
321
+ }
322
+
323
+ setSelectedPaymentTypeIds(nextSelectedIds);
324
+ persistSelectedPaymentTypeIds(nextSelectedIds).catch(error => {
325
+ Alert.alert(
326
+ 'Erro ao gravar configurações',
327
+ error?.message ?? JSON.stringify(error),
328
+ );
329
+ setSelectedPaymentTypeIds(resolveDevicePaymentTypeIds(configs));
330
+ });
331
+ },
332
+ [
333
+ configs,
334
+ disableSelection,
335
+ isSaving,
336
+ selectedPaymentTypeIds,
337
+ persistSelectedPaymentTypeIds,
338
+ ],
339
+ );
340
+
341
+ const hasWallets = wallets.length > 0;
342
+ const hasPaymentTypes = walletPaymentTypes.length > 0;
343
+ const hasVisibleGroups = walletGroups.length > 0;
344
+ const selectionEnabled = !isSaving && !disableSelection;
345
+
346
+ return (
347
+ <View style={localStyles.container}>
348
+ <View style={localStyles.introCard}>
349
+ <View style={localStyles.introHeaderRow}>
350
+ <Text style={localStyles.introTitle}>{title}</Text>
351
+ <DefaultTooltip
352
+ title={title}
353
+ message={`${introText} ${helpText}`.trim()}
354
+ />
355
+ </View>
356
+ </View>
357
+
358
+ {walletsLoading ? (
359
+ <StateStore compact loading={loadingWalletsText} />
360
+ ) : null}
361
+
362
+ {!walletsLoading && walletPaymentTypesLoading ? (
363
+ <StateStore compact loading={loadingPaymentsText} />
364
+ ) : null}
365
+
366
+ {!walletsLoading && !hasWallets && !hasPaymentTypes ? (
367
+ <View style={localStyles.emptyCard}>
368
+ <Text style={localStyles.emptyTitle}>{emptyTitle}</Text>
369
+ <Text style={localStyles.emptyText}>{emptyText}</Text>
370
+ </View>
371
+ ) : null}
372
+
373
+ {hasVisibleGroups ? (
374
+ <View style={localStyles.walletList}>
375
+ {walletGroups.map(group => {
376
+ const walletLabel = group.isUnassigned
377
+ ? unassignedTitle
378
+ : resolveWalletLabel(group.wallet);
379
+
380
+ return (
381
+ <View key={group.key} style={localStyles.walletCard}>
382
+ <View style={localStyles.walletCardHeader}>
383
+ <View style={localStyles.walletMeta}>
384
+ <Text style={localStyles.walletName}>{walletLabel}</Text>
385
+ {!group.isUnassigned && (
386
+ <Text style={localStyles.walletId}>
387
+ {group.walletId ? `ID #${group.walletId}` : ''}
388
+ </Text>
389
+ )}
390
+ </View>
391
+ </View>
392
+
393
+ <View style={localStyles.paymentTypesBlock}>
394
+ <Text style={localStyles.paymentTypesTitle}>
395
+ Meios de pagamento
396
+ </Text>
397
+ {group.paymentTypes.length > 0 ? (
398
+ <View style={localStyles.paymentTypesRow}>
399
+ {group.paymentTypes.map(item => {
400
+ const walletPaymentTypeId = normalizeEntityId(item?.id);
401
+ if (!walletPaymentTypeId) {
402
+ return null;
403
+ }
404
+
405
+ const paymentTypeLabel = resolvePaymentTypeLabel(item);
406
+ const selected = selectedPaymentTypeIdSet.has(
407
+ walletPaymentTypeId,
408
+ );
409
+
410
+ if (!paymentTypeLabel) {
411
+ return null;
412
+ }
413
+
414
+ return (
415
+ <TouchableOpacity
416
+ key={`${group.key}-${walletPaymentTypeId}`}
417
+ activeOpacity={selectionEnabled ? 0.85 : 1}
418
+ disabled={!selectionEnabled}
419
+ onPress={() =>
420
+ handleTogglePaymentType(walletPaymentTypeId)
421
+ }
422
+ style={[
423
+ localStyles.paymentTypeChip,
424
+ selected && localStyles.paymentTypeChipSelected,
425
+ !selectionEnabled && localStyles.paymentTypeChipDisabled,
426
+ ]}>
427
+ <Text
428
+ style={[
429
+ localStyles.paymentTypeChipText,
430
+ selected &&
431
+ localStyles.paymentTypeChipTextSelected,
432
+ ]}>
433
+ {paymentTypeLabel}
434
+ </Text>
435
+ </TouchableOpacity>
436
+ );
437
+ })}
438
+ </View>
439
+ ) : (
440
+ <Text style={localStyles.paymentTypesEmpty}>
441
+ {group.isUnassigned ? unassignedText : emptyPaymentsText}
442
+ </Text>
443
+ )}
444
+ </View>
445
+ </View>
446
+ );
447
+ })}
448
+ </View>
449
+ ) : null}
450
+
451
+ <View style={localStyles.footerHintRow}>
452
+ <Text style={localStyles.footerHint}>
453
+ {selectedPaymentTypeIds.length > 0
454
+ ? `${selectedPaymentTypeIds.length} meio(s) de pagamento liberado(s).`
455
+ : 'Nenhum meio de pagamento liberado ainda.'}
456
+ </Text>
457
+ </View>
458
+ </View>
459
+ );
460
+ };
461
+
462
+ export default PaymentTypesByWalletTab;