@controleonline/ui-common 1.2.71 → 1.2.75

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 (150) hide show
  1. package/.github/actions/workers/manager/action.yml +147 -0
  2. package/.github/actions/workers/qa/action.yml +44 -0
  3. package/.github/actions/workers/security/action.yml +44 -0
  4. package/.github/actions/workers/technical-documenter/action.yml +51 -0
  5. package/.github/workflows/manager-worker.yml +168 -0
  6. package/.github/workflows/publish-npm.yml +45 -0
  7. package/.gitmodules +3 -0
  8. package/AGENTS.md +6 -0
  9. package/README.md +14 -0
  10. package/package.json +3 -2
  11. package/src/api/fetch.js +1 -1
  12. package/src/api/index.js +92 -22
  13. package/src/react/components/AddImportModal.js +94 -110
  14. package/src/react/components/BottomNavigationBar.config.js +211 -231
  15. package/src/react/components/CategoryForm.js +52 -35
  16. package/src/react/components/DefaultProvider.native.js +131 -95
  17. package/src/react/components/DefaultProvider.web.js +148 -74
  18. package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
  19. package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
  20. package/src/react/components/RuntimeInfoFooter.js +100 -36
  21. package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
  22. package/src/react/components/UnifiedPaymentBar.js +7 -4
  23. package/src/react/components/UserAvatar.js +160 -0
  24. package/src/react/components/integrations/IntegrationHero/index.js +48 -0
  25. package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
  26. package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
  27. package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
  28. package/src/react/config/deviceConfigBootstrap.js +5 -3
  29. package/src/react/pages/Connections.js +229 -0
  30. package/src/react/pages/Connections.styles.js +222 -0
  31. package/src/react/pages/DeviceDetailPage.js +2814 -0
  32. package/src/react/pages/DeviceDetailPage.styles.js +308 -0
  33. package/src/react/pages/Devices/currentDevice.js +194 -0
  34. package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
  35. package/src/react/pages/Devices/deviceTypes/all.js +23 -0
  36. package/src/react/pages/Devices/deviceTypes/device.js +25 -0
  37. package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
  38. package/src/react/pages/Devices/deviceTypes/display.js +26 -0
  39. package/src/react/pages/Devices/deviceTypes/index.js +145 -0
  40. package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
  41. package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
  42. package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
  43. package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
  44. package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
  45. package/src/react/pages/Devices.js +183 -0
  46. package/src/react/pages/Devices.styles.js +353 -0
  47. package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
  48. package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
  49. package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
  50. package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
  51. package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
  52. package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
  53. package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
  54. package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
  55. package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
  56. package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
  57. package/src/react/pages/Food99IntegrationPage.js +1 -0
  58. package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
  59. package/src/react/pages/GenericLogPage.js +42 -167
  60. package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
  61. package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
  62. package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
  63. package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
  64. package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
  65. package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
  66. package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
  67. package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
  68. package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
  69. package/src/react/pages/IFoodIntegrationPage.js +1 -0
  70. package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
  71. package/src/react/pages/Imports.js +214 -166
  72. package/src/react/pages/IntegrationConfigPage.js +744 -0
  73. package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
  74. package/src/react/pages/Integrations.js +299 -0
  75. package/src/react/pages/Integrations.styles.js +130 -0
  76. package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
  77. package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
  78. package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
  79. package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
  80. package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
  81. package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
  82. package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
  83. package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
  84. package/src/react/pages/PrinterDeviceFormPage.js +521 -0
  85. package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
  86. package/src/react/pages/WhatsAppConnectionPage.js +459 -0
  87. package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
  88. package/src/react/pages/integrationsCatalog.js +399 -0
  89. package/src/react/services/Cielo/Cielo.js +193 -193
  90. package/src/react/utils/categoryContexts.js +46 -0
  91. package/src/react/utils/entityDisplay.js +222 -217
  92. package/src/react/utils/fileUrl.js +39 -20
  93. package/src/react/utils/integrationPage.js +16 -0
  94. package/src/react/utils/runtimeFooter.js +40 -22
  95. package/src/react/utils/runtimeLanguage.js +50 -9
  96. package/src/react/utils/runtimeMenu.js +191 -131
  97. package/src/react/utils/runtimeZoom.js +43 -0
  98. package/src/react/utils/shopConfig.js +27 -15
  99. package/src/react/utils/shopFranchises.js +126 -1
  100. package/src/react/utils/storeColumns.js +23 -4
  101. package/src/react/utils/userAvatar.js +104 -0
  102. package/src/store/categories/index.js +48 -20
  103. package/src/store/device_config/index.js +62 -21
  104. package/src/store/entity_log/index.js +22 -1
  105. package/src/store/imports/customActions.js +51 -0
  106. package/src/store/imports/index.js +89 -88
  107. package/src/store/status/index.js +11 -11
  108. package/src/store/themes/index.js +22 -0
  109. package/src/store/timezones/index.js +3 -1
  110. package/src/tests/browser/manager/connections.spec.js +143 -0
  111. package/src/tests/browser/manager/devices-current.spec.js +343 -0
  112. package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
  113. package/src/tests/react/api/deviceHeaders.test.js +114 -0
  114. package/src/tests/react/components/AddImportModal.test.js +166 -0
  115. package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
  116. package/src/tests/react/components/UserAvatar.test.js +52 -0
  117. package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
  118. package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
  119. package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
  120. package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
  121. package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
  122. package/src/tests/react/services/Cielo.test.js +190 -190
  123. package/src/tests/react/store/categoriesOrdering.test.js +26 -0
  124. package/src/tests/react/utils/appDomain.test.js +62 -0
  125. package/src/tests/react/utils/entityDisplay.test.js +2 -2
  126. package/src/tests/react/utils/fileUrl.test.js +3 -3
  127. package/src/tests/react/utils/formatter.test.mjs +33 -0
  128. package/src/tests/react/utils/runtimeFooter.test.js +29 -4
  129. package/src/tests/react/utils/runtimeLanguage.test.js +79 -9
  130. package/src/tests/react/utils/runtimeMenu.test.js +198 -134
  131. package/src/tests/react/utils/runtimeZoom.test.js +38 -0
  132. package/src/tests/react/utils/shopConfig.test.js +10 -9
  133. package/src/tests/react/utils/shopFranchises.test.js +43 -0
  134. package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
  135. package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
  136. package/src/tests/react/utils/translate.test.mjs +141 -349
  137. package/src/tests/react/utils/userAvatar.test.js +63 -0
  138. package/src/utils/appDomain.js +15 -4
  139. package/src/utils/formatter.js +104 -16
  140. package/src/utils/integrationConfigs.js +80 -80
  141. package/src/utils/translate.js +222 -438
  142. package/src/utils/translateDiscovery.js +96 -0
  143. package/src/utils/translateNormalize.js +33 -0
  144. package/src/utils/translatePending.js +92 -0
  145. package/src/utils/translateStorage.js +142 -0
  146. package/.github/agents/developer.agent.md +0 -30
  147. package/.github/agents/devops.agent.md +0 -30
  148. package/.github/agents/qa.agent.md +0 -30
  149. package/.github/agents/security.agent.md +0 -30
  150. package/.github/workflows/npmjs.yml +0 -35
package/src/api/index.js CHANGED
@@ -1,10 +1,35 @@
1
1
  import myFetch from '@controleonline/ui-common/src/api/fetch';
2
2
  import axios from 'axios';
3
- import { APP_ENV } from '../../../../../config/env';
3
+ import {env as APP_ENV} from '@env';
4
4
  import { resolveAppDomain } from '@controleonline/ui-common/src/utils/appDomain';
5
5
  import { resolveApiEntryPoint } from '@controleonline/ui-common/src/utils/apiEntryPoint';
6
6
 
7
7
  const MIME_TYPE = 'application/ld+json';
8
+ const DOMAIN_QUERY_PARAM_KEYS = new Set(['app-domain', 'appdomain']);
9
+
10
+ function stripDomainQueryParams(uri) {
11
+ const value = String(uri || '');
12
+ const hashIndex = value.indexOf('#');
13
+ const withoutHash = hashIndex >= 0 ? value.slice(0, hashIndex) : value;
14
+ const hash = hashIndex >= 0 ? value.slice(hashIndex) : '';
15
+ const queryIndex = withoutHash.indexOf('?');
16
+
17
+ if (queryIndex < 0) {
18
+ return value;
19
+ }
20
+
21
+ const path = withoutHash.slice(0, queryIndex);
22
+ const params = new URLSearchParams(withoutHash.slice(queryIndex + 1));
23
+
24
+ for (const key of [...params.keys()]) {
25
+ if (DOMAIN_QUERY_PARAM_KEYS.has(String(key || '').trim().toLowerCase())) {
26
+ params.delete(key);
27
+ }
28
+ }
29
+
30
+ const query = params.toString();
31
+ return `${path}${query ? `?${query}` : ''}${hash}`;
32
+ }
8
33
 
9
34
  function encodeBasicAuth(user, password) {
10
35
  const credentials = `${String(user || '').trim()}:${String(password || '').trim()}`;
@@ -36,13 +61,26 @@ function resolveApiRuntimeConfig(config = {}) {
36
61
  function buildApiUrl(apiBaseUrl, path) {
37
62
  const apiEntryPoint = resolveApiEntryPoint(apiBaseUrl);
38
63
  const entryPoint = apiEntryPoint + (apiEntryPoint.endsWith('/') ? '' : '/');
39
- const normalizedPath = String(path || '').startsWith('/')
64
+ const rawPath = String(path || '').startsWith('/')
40
65
  ? String(path || '').substring(1)
41
66
  : String(path || '');
67
+ const normalizedPath = stripDomainQueryParams(rawPath);
42
68
 
43
69
  return new URL(normalizedPath, entryPoint).href;
44
70
  }
45
71
 
72
+ function resolveRequestDevice(masterDevice, device, bodyDeviceId) {
73
+ if (masterDevice?.id) {
74
+ return masterDevice;
75
+ }
76
+
77
+ if (device?.id) {
78
+ return device;
79
+ }
80
+
81
+ return bodyDeviceId ? {id: bodyDeviceId} : null;
82
+ }
83
+
46
84
  async function readSmokeResponseBody(response, responseType) {
47
85
  if (responseType === 'blob') {
48
86
  return await response.blob();
@@ -242,9 +280,22 @@ export const api = {
242
280
  }
243
281
  }
244
282
 
245
- const headerDeviceId =
246
- this.masterDevice?.id || this.device?.id || bodyDeviceId;
247
- if (headerDeviceId) options.headers.set('DEVICE', headerDeviceId);
283
+ const requestDevice = resolveRequestDevice(
284
+ this.masterDevice,
285
+ this.device,
286
+ bodyDeviceId,
287
+ );
288
+
289
+ if (requestDevice?.id) {
290
+ options.headers.set('DEVICE', requestDevice.id);
291
+
292
+ const requestDeviceType = String(requestDevice.type || '')
293
+ .trim()
294
+ .toUpperCase();
295
+ if (requestDeviceType !== '') {
296
+ options.headers.set('DEVICE-TYPE', requestDeviceType);
297
+ }
298
+ }
248
299
  if (options.responseType != 'text') {
249
300
  options.headers.set('Content-Type', MIME_TYPE);
250
301
  options.headers.set('Accept', MIME_TYPE);
@@ -254,9 +305,11 @@ export const api = {
254
305
  if (options.body && typeof options.body != 'string') {
255
306
  options.body = JSON.stringify(options.body);
256
307
  }
257
- if (options.params) {
258
- uri = this.buildQueryString(uri, options);
259
- }
308
+ uri = stripDomainQueryParams(uri);
309
+
310
+ if (options.params) {
311
+ uri = this.buildQueryString(uri, options);
312
+ }
260
313
  return myFetch(uri, options).catch(e => {
261
314
  throw e;
262
315
  });
@@ -279,13 +332,18 @@ export const api = {
279
332
 
280
333
  return session?.token || session?.api_key;
281
334
  },
282
- serialize(obj, prefix = '') {
283
- const pairs = [];
284
-
285
- for (const key in obj) {
286
- if (obj.hasOwnProperty(key)) {
287
- const value = obj[key];
288
- let fullKey = prefix ? `${prefix}.${key}` : key; // Usa ponto para objetos
335
+ serialize(obj, prefix = '') {
336
+ const pairs = [];
337
+
338
+ for (const key in obj) {
339
+ if (obj.hasOwnProperty(key)) {
340
+ const normalizedKey = String(key || '').trim().toLowerCase();
341
+ if (DOMAIN_QUERY_PARAM_KEYS.has(normalizedKey)) {
342
+ continue;
343
+ }
344
+
345
+ const value = obj[key];
346
+ let fullKey = prefix ? `${prefix}.${key}` : key; // Usa ponto para objetos
289
347
 
290
348
  if (value === null || value === undefined) {
291
349
  pairs.push(`${fullKey}=`);
@@ -314,13 +372,25 @@ export const api = {
314
372
  return pairs;
315
373
  },
316
374
 
317
- buildQueryString(uri, options) {
318
- if (options.params) {
319
- const params = this.serialize(options.params);
320
- uri = `${uri}?${params.join('&')}`;
321
- }
322
- return uri;
323
- },
375
+ buildQueryString(uri, options) {
376
+ const safeUri = stripDomainQueryParams(uri);
377
+
378
+ if (options.params) {
379
+ const params = this.serialize(options.params);
380
+ if (params.length === 0) {
381
+ return safeUri;
382
+ }
383
+
384
+ const hashIndex = safeUri.indexOf('#');
385
+ const withoutHash = hashIndex >= 0 ? safeUri.slice(0, hashIndex) : safeUri;
386
+ const hash = hashIndex >= 0 ? safeUri.slice(hashIndex) : '';
387
+ const separator = withoutHash.includes('?') ? '&' : '?';
388
+
389
+ return `${withoutHash}${separator}${params.join('&')}${hash}`;
390
+ }
391
+
392
+ return safeUri;
393
+ },
324
394
  post: async function (uri, body = {}) {
325
395
  const options = {
326
396
  method: 'POST',
@@ -1,108 +1,68 @@
1
- import React, { useState } from 'react';
2
- import {
3
- View,
4
- Text,
5
- TouchableOpacity,
6
- ScrollView,
7
- ActivityIndicator,
8
- Platform,
9
- } from 'react-native';
10
-
11
- import Icon from 'react-native-vector-icons/MaterialIcons';
12
- import * as DocumentPicker from 'expo-document-picker';
1
+ import React from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ ScrollView,
7
+ ActivityIndicator,
8
+ } from 'react-native';
9
+
10
+ import Icon from 'react-native-vector-icons/MaterialIcons';
13
11
  import { useStore } from '@store';
14
12
  import AnimatedModal from './AnimatedModal';
15
- import { api } from '@controleonline/ui-common/src/api';
16
13
  import { useMessage } from '@controleonline/ui-common/src/react/components/MessageService';
14
+ import DefaultUpload from '@controleonline/ui-default/src/react/components/upload/DefaultUpload';
17
15
  import styles from './AddImportModal.styles';
18
-
19
- const AddImportModal = ({ visible, onClose, onSuccess, context = {} }) => {
20
- const { showError, showSuccess } = useMessage();
21
- const peopleStore = useStore('people');
22
- const getters = peopleStore.getters;
23
- const { currentCompany } = getters;
24
-
25
- const [file, setFile] = useState(null);
26
- const [loading, setLoading] = useState(false);
16
+
17
+ const AddImportModal = ({ visible, onClose, onSuccess, context = {} }) => {
18
+ const { showError, showSuccess } = useMessage();
19
+ const peopleStore = useStore('people');
20
+ const importsStore = useStore('imports');
21
+ const themeStore = useStore('theme');
22
+ const getters = peopleStore.getters;
23
+ const { currentCompany } = getters;
24
+ const importActions = importsStore.actions || {};
25
+ const themeColors = themeStore?.getters?.colors || {};
26
+ const buttonPalette = {
27
+ buttonBackground: themeColors.buttonBackground,
28
+ buttonBorder: themeColors.buttonBorder,
29
+ buttonText: themeColors.buttonText,
30
+ buttonIcon: themeColors.buttonIcon || themeColors.buttonText,
31
+ };
32
+
27
33
  const modalTitle = global.t?.t('imports', 'title', 'new_import');
28
34
  const csvLabel = global.t?.t('imports', 'label', 'csv_file');
29
35
  const selectFileLabel = global.t?.t('imports', 'button', 'select_file');
30
36
  const cancelLabel = global.t?.t('imports', 'button', 'cancel');
31
- const importLabel = global.t?.t('imports', 'button', 'import');
32
37
  const csvOnlyLabel = global.t?.t('imports', 'message', 'only_csv_files_are_allowed');
33
- const pickFileErrorLabel = global.t?.t('imports', 'error', 'error_selecting_file');
34
38
  const importSuccessLabel = global.t?.t('imports', 'success', 'import_sent_successfully');
35
39
  const importErrorLabel = global.t?.t('imports', 'error', 'error_sending_import');
36
- const missingFileLabel = global.t?.t('imports', 'error', 'select_a_csv_file');
37
-
38
- const handlePickFile = async () => {
39
- try {
40
- const result = await DocumentPicker.getDocumentAsync({
41
- type: 'text/csv',
42
- copyToCacheDirectory: true,
43
- multiple: false,
44
- });
45
-
46
- if (result.canceled) return;
47
-
48
- const pickedFile = result.assets[0];
49
-
50
- if (!pickedFile.name?.toLowerCase().endsWith('.csv')) {
51
- showError(csvOnlyLabel);
52
- return;
53
- }
54
-
55
- setFile(pickedFile);
56
- } catch {
57
- showError(pickFileErrorLabel);
58
- }
59
- };
60
40
 
61
- const handleSave = async () => {
62
- if (!file) {
63
- showError(missingFileLabel);
64
- return;
41
+ const handleUploadImportFile = async ({ file }) => {
42
+ if (!file?.name?.toLowerCase().endsWith('.csv')) {
43
+ throw new Error(csvOnlyLabel);
65
44
  }
66
-
67
- setLoading(true);
68
-
69
- try {
70
- const formData = new FormData();
71
- formData.append('importType', context.context);
72
-
73
-
74
- formData.append('people', String(currentCompany.id));
75
-
76
-
77
- if (Platform.OS === 'web') {
78
- const response = await fetch(file.uri);
79
- const blob = await response.blob();
80
- formData.append('file', blob, file.name || 'import.csv');
81
- } else {
82
- formData.append('file', {
83
- uri: file.uri,
84
- name: file.name || 'import.csv',
85
- type: file.mimeType || 'text/csv',
86
- });
87
- }
88
45
 
89
- await api.upload('/imports/upload', formData);
46
+ try {
47
+ await importActions.uploadImportFile({
48
+ file,
49
+ importType: context.context,
50
+ peopleId: currentCompany.id,
51
+ });
90
52
  showSuccess(importSuccessLabel);
91
53
  if (onSuccess) onSuccess();
92
54
  handleClose();
55
+ return file;
93
56
  } catch {
94
- showError(importErrorLabel);
95
- } finally {
96
- setLoading(false);
57
+ throw new Error(importErrorLabel);
97
58
  }
98
- };
99
-
100
- const handleClose = () => {
101
- setFile(null);
102
- onClose();
103
- };
104
-
105
- return (
59
+ };
60
+
61
+ const handleClose = () => {
62
+ onClose();
63
+ };
64
+
65
+ return (
106
66
  <AnimatedModal
107
67
  visible={visible}
108
68
  onRequestClose={handleClose}
@@ -118,15 +78,50 @@ const AddImportModal = ({ visible, onClose, onSuccess, context = {} }) => {
118
78
 
119
79
  <ScrollView style={styles.content}>
120
80
  <Text style={styles.label}>{csvLabel}</Text>
121
- <TouchableOpacity
122
- onPress={handlePickFile}
123
- style={styles.filePicker}
124
- >
125
- <Text numberOfLines={1} style={styles.fileName}>
126
- {file ? file.name : selectFileLabel}
127
- </Text>
128
- <Icon name="upload-file" size={22} color={file ? "#007bff" : "#666"} />
129
- </TouchableOpacity>
81
+ <DefaultUpload
82
+ relationStoreName="imports"
83
+ relationField="import"
84
+ relationResource="imports"
85
+ entityId={context.context || 'import'}
86
+ companyId={currentCompany.id}
87
+ context={`imports-${context.context || 'default'}`}
88
+ libraryContexts={[`imports-${context.context || 'default'}`]}
89
+ acceptedTypes="text/csv,.csv"
90
+ fileType=""
91
+ title={csvLabel}
92
+ triggerLabel={selectFileLabel}
93
+ managerTitle={modalTitle}
94
+ searchPlaceholder={selectFileLabel}
95
+ uploadButtonLabel={selectFileLabel}
96
+ emptyAttachmentLabel=""
97
+ emptyLibraryLabel={selectFileLabel}
98
+ showInlineContent={false}
99
+ uploadResultAlreadyAttached
100
+ requireEntity={false}
101
+ onUploadFile={handleUploadImportFile}
102
+ renderTrigger={({openManager, uploading}) => (
103
+ <TouchableOpacity
104
+ onPress={openManager}
105
+ disabled={uploading}
106
+ style={[
107
+ styles.filePicker,
108
+ {
109
+ backgroundColor: buttonPalette.buttonBackground,
110
+ borderColor: buttonPalette.buttonBorder,
111
+ },
112
+ ]}
113
+ >
114
+ <Text numberOfLines={1} style={[styles.fileName, { color: buttonPalette.buttonText }]}>
115
+ {selectFileLabel}
116
+ </Text>
117
+ {uploading ? (
118
+ <ActivityIndicator color={buttonPalette.buttonIcon} />
119
+ ) : (
120
+ <Icon name="upload-file" size={22} color={buttonPalette.buttonIcon} />
121
+ )}
122
+ </TouchableOpacity>
123
+ )}
124
+ />
130
125
  <Text style={styles.helperText}>
131
126
  {csvOnlyLabel}
132
127
  </Text>
@@ -136,22 +131,11 @@ const AddImportModal = ({ visible, onClose, onSuccess, context = {} }) => {
136
131
  <TouchableOpacity onPress={handleClose} style={styles.secondaryButton}>
137
132
  <Text>{cancelLabel}</Text>
138
133
  </TouchableOpacity>
139
-
140
- <TouchableOpacity
141
- onPress={handleSave}
142
- disabled={loading}
143
- style={[
144
- styles.primaryButton,
145
- loading && styles.primaryButtonDisabled,
146
- ]}
147
- >
148
- {loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.primaryButtonText}>{importLabel}</Text>}
149
- </TouchableOpacity>
150
134
  </View>
151
135
  </View>
152
- </AnimatedModal>
153
- );
154
- };
155
-
136
+ </AnimatedModal>
137
+ );
138
+ };
139
+
156
140
  export default AddImportModal;
157
141
  // TODO(store-first): quando este arquivo for mexido, mover a leitura para stores e evitar chamadas HTTP diretas quando o store ja resolver isso.