@controleonline/ui-common 1.2.86 → 1.2.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/integration-source-gate.yml +68 -0
- package/.github/workflows/manager-worker.yml +7 -156
- package/.github/workflows/publish-npm.yml +73 -27
- package/.github/workflows/pull-request-checks.yml +7 -5
- package/docs/technical/Device-Detail-Alias-UI-Sync.md +141 -0
- package/package.json +13 -8
- package/src/react/components/AddImportModal.js +61 -34
- package/src/react/components/BottomNavigationBar.js +178 -174
- package/src/react/components/BottomNavigationBar.styles.js +139 -118
- package/src/react/components/DefaultProvider.native.js +427 -421
- package/src/react/components/DefaultProvider.web.js +131 -125
- package/src/react/components/RemoteCheckoutService.js +3 -3
- package/src/react/components/RuntimeFooterMarqueeText.js +88 -36
- package/src/react/components/RuntimeInfoFooter.js +76 -43
- package/src/react/components/RuntimeInfoFooter.styles.js +22 -14
- package/src/react/config/deviceConfigBootstrap.js +3 -3
- package/src/react/pages/Devices/detail/DeviceDetailAlertsCommandsSection.js +4 -22
- package/src/react/pages/Devices/detail/DeviceDetailMovementSections.js +6 -2
- package/src/react/pages/Devices/detail/DeviceDetailOrdersPrintSection.js +4 -0
- package/src/react/pages/Devices/detail/DeviceDetailScreen.js +23 -338
- package/src/react/pages/Devices/detail/createDeviceDetailContext.js +20 -0
- package/src/react/pages/Devices/detail/useDeviceDetailActions.js +11 -36
- package/src/react/pages/Devices/detail/useDeviceDetailLoaders.js +129 -37
- package/src/react/pages/Devices/detail/useDeviceDetailSaves.js +11 -38
- package/src/react/pages/Devices/detail/useDeviceDetailStateA.js +9 -28
- package/src/react/pages/Imports.js +13 -11
- package/src/react/pages/IntegrationConfigFields.js +1 -0
- package/src/react/pages/IntegrationConfigPage.js +101 -45
- package/src/react/pages/IntegrationConfigPage.utils.js +21 -13
- package/src/react/pages/fetchPeopleConfigs.js +21 -0
- package/src/react/pages/integrationsCatalog.js +15 -110
- package/src/react/services/Cielo/Cielo.js +9 -9
- package/src/react/services/Getnet/Getnet.web.js +25 -0
- package/src/react/utils/companyAuthority.js +36 -0
- package/src/react/utils/fileUrl.js +14 -5
- package/src/react/utils/paymentDevices.js +375 -270
- package/src/react/utils/printerDevices.js +2 -2
- package/src/react/utils/runtimeFooter.js +178 -224
- package/src/react/utils/runtimeFooterText.js +160 -0
- package/src/react/utils/runtimeLanguage.js +5 -5
- package/src/react/utils/runtimeZoom.js +29 -5
- package/src/react/utils/shopFranchises.js +167 -12
- package/src/react/utils/storeColumns.js +235 -217
- package/src/react/utils/systemErrorMessage.js +2 -1
- package/src/store/imports/customActions.js +42 -2
- package/src/store/integration/index.js +43 -0
- package/src/tests/browser/manager/device-detail-apply-config-defined.spec.js +31 -0
- package/src/tests/browser/manager/device-detail-composition.spec.js +295 -0
- package/src/tests/browser/manager/device-detail-copy-config.spec.js +11 -1
- package/src/tests/browser/manager/device-detail-pdv-current-company.spec.js +273 -0
- package/src/tests/browser/manager/runtime-footer-rotation.spec.js +397 -0
- package/src/tests/react/components/DefaultProviderAuthority.test.js +28 -0
- package/src/tests/react/components/RuntimeFooterMarqueeText.build.test.js +29 -0
- package/src/tests/react/config/deviceConfigBootstrap.test.js +24 -1
- package/src/tests/react/pages/applyCurrentDeviceConfig.test.js +85 -0
- package/src/tests/react/pages/deviceDetailComposition.test.js +65 -0
- package/src/tests/react/pages/deviceDetailHookDependencies.test.mjs +31 -0
- package/src/tests/react/pages/deviceDetailLoaderDependencies.test.mjs +28 -0
- package/src/tests/react/pages/receitaFederalIntegrationContract.test.mjs +27 -6
- package/src/tests/react/services/Cielo.test.js +2 -2
- package/src/tests/react/utils/companyAuthority.test.js +53 -0
- package/src/tests/react/utils/formatter.test.mjs +6 -0
- package/src/tests/react/utils/paymentDevices.test.js +72 -0
- package/src/tests/react/utils/runtimeFooter.test.js +35 -0
- package/src/tests/react/utils/runtimeFooterText.test.js +88 -0
- package/src/tests/react/utils/runtimeLanguage.test.js +4 -4
- package/src/tests/react/utils/runtimeZoom.test.js +20 -0
- package/src/tests/react/utils/shopFranchises.test.js +32 -13
- package/src/tests/react/utils/translate.test.mjs +6 -6
- package/src/utils/formatter.js +7 -3
- package/src/utils/translate.js +16 -16
- package/src/utils/translatePending.js +6 -6
- package/src/utils/translateStorage.js +2 -2
|
@@ -1,44 +1,17 @@
|
|
|
1
|
-
import { useCallback,
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { resolveThemePalette } from '@controleonline/../../src/styles/branding';
|
|
6
|
-
import { colors } from '@controleonline/../../src/styles/colors';
|
|
7
|
-
import packageJson from '@package';
|
|
8
|
-
import {
|
|
9
|
-
canDisplayChangePrinter, DEVICE_ANDROID_KIOSK_ENABLED_CONFIG_KEY, DEVICE_ANDROID_LAUNCHER_ENABLED_CONFIG_KEY,
|
|
10
|
-
DISPLAY_AUTO_PRINT_PRODUCT_CONFIG_KEY, DISPLAY_ALLOW_PRINTER_CHANGE_CONFIG_KEY, DEVICE_ALERT_SOUND_ENABLED_KEY,
|
|
11
|
-
DEVICE_ALERT_SOUND_URL_KEY, DEVICE_ORDER_VISIBILITY_COMPANY, DEVICE_ORDER_VISIBILITY_DEVICE, DEVICE_ORDER_VISIBILITY_KEY,
|
|
12
|
-
DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY, isPosAutoPrintEnabled, isPosCashRegisterOpen, isTruthyValue, parseConfigsObject,
|
|
13
|
-
POS_AUTO_PRINT_ENABLED_CONFIG_KEY, POS_CASH_MANAGEMENT_MODE_CASH_REGISTER, POS_CASH_MANAGEMENT_MODE_CONFIG_KEY,
|
|
14
|
-
POS_CASH_MANAGEMENT_MODE_DAILY, POS_CHECK_ORDER_MANAGEMENT_MODE_CONFIG_KEY, POS_CHECK_ORDER_MANAGEMENT_MODE_EXISTING_ONLY,
|
|
15
|
-
POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE, POS_CHECK_ORDER_TYPE_CONFIG_KEY, POS_CHECK_ORDER_TYPE_NONE, POS_CHECK_ORDER_TYPE_TAB,
|
|
16
|
-
POS_CHECK_ORDER_TYPE_TABLE, POS_CHECK_ORDER_TYPE_STAMP, POS_DELIVERY_ENABLED_CONFIG_KEY, POS_OPERATION_MODE_COUNTER,
|
|
17
|
-
POS_OPERATION_MODE_CONFIG_KEY, POS_OPERATION_MODE_OPTIONS, POS_PRODUCT_SHOWCASE_CONFIG_KEY, POS_PRINT_MODE_FORM,
|
|
18
|
-
POS_PRINT_MODE_ORDER, getPosOperationModeOption, isAndroidKioskEnabled, isAndroidLauncherEnabled, isPosDeliveryEnabled,
|
|
19
|
-
resolvePosCheckOrderManagementMode, resolvePosCheckOrderType, resolvePosCheckOrderTypeForShop, resolveDeviceOrderVisibility,
|
|
20
|
-
resolvePosCashManagementMode, resolvePosOperationMode, resolvePosPrintMode,
|
|
21
|
-
} from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
|
|
22
|
-
import {
|
|
23
|
-
filterDeviceConfigsByCompany, getCompanyPaymentDeviceOptions, getPaymentGatewayFromConfigs, getPaymentGatewayLabel,
|
|
24
|
-
isPaymentCapableDeviceConfig, isPdvPrinterEnabled, normalizeDeviceId, normalizeEntityId, PAYMENT_TYPE_IDS_CONFIG_KEY,
|
|
25
|
-
PAYMENT_GATEWAY_CIELO, PDV_PRINTER_ENABLED_CONFIG_KEY, ORDER_PAYMENT_DEVICE_CONFIG_KEY, POS_GATEWAY_CONFIG_KEY,
|
|
26
|
-
} from '@controleonline/ui-common/src/react/utils/paymentDevices';
|
|
27
|
-
import { normalizeBooleanConfig, SHOP_LOYALTY_COUPONS_ENABLED_CONFIG_KEY } from '@controleonline/ui-common/src/react/utils/shopConfig';
|
|
28
|
-
import { getPrinterOptionValue, getDeviceTypeLabel, getPrinterLabel, getPrinterOptions } from '@controleonline/ui-common/src/react/utils/printerDevices';
|
|
29
|
-
import { hex, DISPLAY_DEVICE_TYPE, PDV_DEVICE_TYPE, DISPLAY_DEVICE_LINK_CONFIG_KEY, DISPLAY_DEVICE_PRINTER_CONFIG_KEY,
|
|
30
|
-
PDV_TAB_OPERATION, PDV_TAB_ORDERS, PDV_TAB_DEVICE, PDV_TAB_PAYMENT_TYPES, PDV_TAB_MOVEMENT, PDV_DETAIL_TABS, tt,
|
|
31
|
-
} from './deviceDetailConstants';
|
|
32
|
-
import { paymentIcon, formatApiError, getDisplayLabel, getProductShowcaseLabel, getIsOpen, confirm } from './deviceDetailHelpers';
|
|
33
|
-
import { api } from '@controleonline/ui-common/src/api';
|
|
34
|
-
import { buildDeviceAliasStoreUpdates } from '@controleonline/ui-common/src/react/utils/deviceAliasSync';
|
|
35
|
-
import { createDeviceDetailRenderers } from './DeviceDetailRenderers';
|
|
36
|
-
import { Alert, Platform } from 'react-native';
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { DEVICE_ANDROID_LAUNCHER_ENABLED_CONFIG_KEY, DISPLAY_AUTO_PRINT_PRODUCT_CONFIG_KEY, DISPLAY_ALLOW_PRINTER_CHANGE_CONFIG_KEY, DEVICE_ALERT_SOUND_ENABLED_KEY, DEVICE_ALERT_SOUND_URL_KEY, DEVICE_ORDER_VISIBILITY_DEVICE, DEVICE_ORDER_VISIBILITY_KEY, DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY, POS_DELIVERY_ENABLED_CONFIG_KEY } from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
|
|
4
|
+
import { normalizeDeviceId, PAYMENT_GATEWAY_CIELO } from '@controleonline/ui-common/src/react/utils/paymentDevices';
|
|
37
5
|
|
|
6
|
+
import { hex, DISPLAY_DEVICE_LINK_CONFIG_KEY, DISPLAY_DEVICE_PRINTER_CONFIG_KEY, PDV_TAB_OPERATION, PDV_TAB_ORDERS, PDV_TAB_DEVICE, PDV_TAB_PAYMENT_TYPES, PDV_TAB_MOVEMENT } from './deviceDetailConstants';
|
|
7
|
+
import { confirm } from './deviceDetailHelpers';
|
|
8
|
+
|
|
9
|
+
import { createDeviceDetailRenderers } from './DeviceDetailRenderers';
|
|
38
10
|
|
|
39
11
|
export default function useDeviceDetailSaves(deps) {
|
|
40
12
|
const {
|
|
41
|
-
|
|
13
|
+
themeColors,
|
|
14
|
+
navigation, deviceId, deviceConfigStore, messageApi, websocketActions, runtimeCompanyConfigs, showSystemError, loyaltyCouponsEnabled, currentCompany, currentDevice, currentDeviceConfig, deviceString, deviceType,
|
|
42
15
|
normalizedInitialConfigs, initialAlias, isDisplayDevice, isPdvDevice, actionsRef, stampAutoDisableSignatureRef, brandColors, products, setProducts, productShowcases, setProductShowcases, companyDeviceConfigs,
|
|
43
16
|
setCompanyDeviceConfigs, inflowData, setInflowData, configs, setConfigs, loadingConfigData, setLoadingConfigData, loadingCompanyDeviceConfigs, setLoadingCompanyDeviceConfigs, loadingMovementData, setLoadingMovementData, actionLoading,
|
|
44
17
|
setActionLoading, activePdvTab, setActivePdvTab, savingPaymentTarget, setSavingPaymentTarget, savingPdvSettings, setSavingPdvSettings, savingPaymentTypes, setSavingPaymentTypes, savingPosOperationMode, setSavingPosOperationMode, savingProductShowcase,
|
|
@@ -401,8 +374,8 @@ export default function useDeviceDetailSaves(deps) {
|
|
|
401
374
|
const { renderProduct, renderHelpButton, renderSwitchRow, renderOptionButtons } =
|
|
402
375
|
createDeviceDetailRenderers({ themeColors, palette: brandColors });
|
|
403
376
|
|
|
404
|
-
|
|
405
377
|
return {
|
|
378
|
+
renderProduct, renderHelpButton, renderSwitchRow, renderOptionButtons,
|
|
406
379
|
saveLauncherMode,
|
|
407
380
|
saveDeviceAlertSoundConfig,
|
|
408
381
|
saveDeviceOrderVisibility,
|
|
@@ -5,36 +5,14 @@ import { useMessage } from '@controleonline/ui-common/src/react/components/Messa
|
|
|
5
5
|
import { resolveThemePalette } from '@controleonline/../../src/styles/branding';
|
|
6
6
|
import { colors } from '@controleonline/../../src/styles/colors';
|
|
7
7
|
import packageJson from '@package';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
DISPLAY_AUTO_PRINT_PRODUCT_CONFIG_KEY, DISPLAY_ALLOW_PRINTER_CHANGE_CONFIG_KEY, DEVICE_ALERT_SOUND_ENABLED_KEY,
|
|
11
|
-
DEVICE_ALERT_SOUND_URL_KEY, DEVICE_ORDER_VISIBILITY_COMPANY, DEVICE_ORDER_VISIBILITY_DEVICE, DEVICE_ORDER_VISIBILITY_KEY,
|
|
12
|
-
DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY, isPosAutoPrintEnabled, isPosCashRegisterOpen, isTruthyValue, parseConfigsObject,
|
|
13
|
-
POS_AUTO_PRINT_ENABLED_CONFIG_KEY, POS_CASH_MANAGEMENT_MODE_CASH_REGISTER, POS_CASH_MANAGEMENT_MODE_CONFIG_KEY,
|
|
14
|
-
POS_CASH_MANAGEMENT_MODE_DAILY, POS_CHECK_ORDER_MANAGEMENT_MODE_CONFIG_KEY, POS_CHECK_ORDER_MANAGEMENT_MODE_EXISTING_ONLY,
|
|
15
|
-
POS_CHECK_ORDER_MANAGEMENT_MODE_MANAGE, POS_CHECK_ORDER_TYPE_CONFIG_KEY, POS_CHECK_ORDER_TYPE_NONE, POS_CHECK_ORDER_TYPE_TAB,
|
|
16
|
-
POS_CHECK_ORDER_TYPE_TABLE, POS_CHECK_ORDER_TYPE_STAMP, POS_DELIVERY_ENABLED_CONFIG_KEY, POS_OPERATION_MODE_COUNTER,
|
|
17
|
-
POS_OPERATION_MODE_CONFIG_KEY, POS_OPERATION_MODE_OPTIONS, POS_PRODUCT_SHOWCASE_CONFIG_KEY, POS_PRINT_MODE_FORM,
|
|
18
|
-
POS_PRINT_MODE_ORDER, getPosOperationModeOption, isAndroidKioskEnabled, isAndroidLauncherEnabled, isPosDeliveryEnabled,
|
|
19
|
-
resolvePosCheckOrderManagementMode, resolvePosCheckOrderType, resolvePosCheckOrderTypeForShop, resolveDeviceOrderVisibility,
|
|
20
|
-
resolvePosCashManagementMode, resolvePosOperationMode, resolvePosPrintMode,
|
|
21
|
-
} from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
|
|
22
|
-
import {
|
|
23
|
-
filterDeviceConfigsByCompany, getCompanyPaymentDeviceOptions, getPaymentGatewayFromConfigs, getPaymentGatewayLabel,
|
|
24
|
-
isPaymentCapableDeviceConfig, isPdvPrinterEnabled, normalizeDeviceId, normalizeEntityId, PAYMENT_TYPE_IDS_CONFIG_KEY,
|
|
25
|
-
PAYMENT_GATEWAY_CIELO, PDV_PRINTER_ENABLED_CONFIG_KEY, ORDER_PAYMENT_DEVICE_CONFIG_KEY, POS_GATEWAY_CONFIG_KEY,
|
|
26
|
-
} from '@controleonline/ui-common/src/react/utils/paymentDevices';
|
|
8
|
+
import { canDisplayChangePrinter, DISPLAY_AUTO_PRINT_PRODUCT_CONFIG_KEY, DEVICE_ALERT_SOUND_ENABLED_KEY, DEVICE_ALERT_SOUND_URL_KEY, DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY, isPosAutoPrintEnabled, isTruthyValue, parseConfigsObject, POS_PRODUCT_SHOWCASE_CONFIG_KEY, getPosOperationModeOption, isAndroidKioskEnabled, isAndroidLauncherEnabled, isPosDeliveryEnabled, resolvePosCheckOrderManagementMode, resolvePosCheckOrderTypeForShop, resolveDeviceOrderVisibility, resolvePosCashManagementMode, resolvePosOperationMode, resolvePosPrintMode } from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
|
|
9
|
+
import { filterDeviceConfigsByCompany, getCompanyPaymentDeviceOptions, getPaymentGatewayFromConfigs, isPaymentCapableDeviceConfig, isPdvPrinterEnabled, normalizeDeviceId, normalizeEntityId, ORDER_PAYMENT_DEVICE_CONFIG_KEY } from '@controleonline/ui-common/src/react/utils/paymentDevices';
|
|
27
10
|
import { normalizeBooleanConfig, SHOP_LOYALTY_COUPONS_ENABLED_CONFIG_KEY } from '@controleonline/ui-common/src/react/utils/shopConfig';
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
} from './deviceDetailConstants';
|
|
32
|
-
import { paymentIcon, formatApiError, getDisplayLabel, getProductShowcaseLabel, getIsOpen, confirm } from './deviceDetailHelpers';
|
|
33
|
-
import { api } from '@controleonline/ui-common/src/api';
|
|
34
|
-
import { buildDeviceAliasStoreUpdates } from '@controleonline/ui-common/src/react/utils/deviceAliasSync';
|
|
35
|
-
import { createDeviceDetailRenderers } from './DeviceDetailRenderers';
|
|
36
|
-
import { Alert, Platform } from 'react-native';
|
|
11
|
+
import { getPrinterOptions } from '@controleonline/ui-common/src/react/utils/printerDevices';
|
|
12
|
+
import { DISPLAY_DEVICE_TYPE, PDV_DEVICE_TYPE, DISPLAY_DEVICE_LINK_CONFIG_KEY, DISPLAY_DEVICE_PRINTER_CONFIG_KEY, PDV_TAB_OPERATION } from './deviceDetailConstants';
|
|
13
|
+
import { formatApiError, getIsOpen } from './deviceDetailHelpers';
|
|
37
14
|
|
|
15
|
+
import { Platform } from 'react-native';
|
|
38
16
|
|
|
39
17
|
export default function useDeviceDetailStateA() {
|
|
40
18
|
const route = useRoute();
|
|
@@ -485,5 +463,8 @@ export default function useDeviceDetailStateA() {
|
|
|
485
463
|
runtimeDeviceId,
|
|
486
464
|
runtimeDeviceType,
|
|
487
465
|
currentCompany,
|
|
466
|
+
runtimeDevice, runtimeDeviceConfig, themeColors,
|
|
467
|
+
displayStore,
|
|
468
|
+
printerStore,
|
|
488
469
|
};
|
|
489
470
|
}
|
|
@@ -27,7 +27,7 @@ const {
|
|
|
27
27
|
|
|
28
28
|
const formatDate = (dateString) => {
|
|
29
29
|
const d = new Date(dateString);
|
|
30
|
-
return d.toLocaleString();
|
|
30
|
+
return d.toLocaleString();
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
const Imports = ({ context = {}, onClose }) => {
|
|
@@ -57,6 +57,12 @@ const Imports = ({ context = {}, onClose }) => {
|
|
|
57
57
|
const importType = context.context;
|
|
58
58
|
const title = context.title;
|
|
59
59
|
const searchPlaceholder = context.searchPlaceholder;
|
|
60
|
+
const allowedExtensions = Array.isArray(context.allowedExtensions)
|
|
61
|
+
? context.allowedExtensions
|
|
62
|
+
: importType === 'invoice_tax' || importType === 'xml'
|
|
63
|
+
? ['xml', 'zip']
|
|
64
|
+
: ['csv'];
|
|
65
|
+
const showCsvTemplate = allowedExtensions.includes('csv');
|
|
60
66
|
const {
|
|
61
67
|
refreshLabel,
|
|
62
68
|
processingLabel,
|
|
@@ -255,11 +261,9 @@ const Imports = ({ context = {}, onClose }) => {
|
|
|
255
261
|
});
|
|
256
262
|
|
|
257
263
|
const csvText = typeof response === 'string' ? response : await response.text?.();
|
|
258
|
-
console.log('CSV recebido:', csvText.slice(0, 200));
|
|
259
264
|
|
|
260
265
|
if (!csvText) throw new Error('CSV vazio');
|
|
261
266
|
|
|
262
|
-
// mobile: verifica se o diretório está disponível
|
|
263
267
|
const dirUri = Directory?.cacheDocumentDirectory || Directory?.documentDirectory;
|
|
264
268
|
|
|
265
269
|
if (dirUri) {
|
|
@@ -272,21 +276,18 @@ const Imports = ({ context = {}, onClose }) => {
|
|
|
272
276
|
await Sharing.shareAsync(fileUri);
|
|
273
277
|
}
|
|
274
278
|
|
|
275
|
-
console.log(`Arquivo CSV criado em: ${fileUri}`);
|
|
276
279
|
return fileUri;
|
|
277
280
|
} else if (typeof window !== 'undefined') {
|
|
278
|
-
// fallback web
|
|
279
281
|
const blob = new Blob([csvText], { type: 'text/csv' });
|
|
280
282
|
const link = document.createElement('a');
|
|
281
283
|
link.href = URL.createObjectURL(blob);
|
|
282
284
|
link.download = `modelo_${importType}.csv`;
|
|
283
285
|
link.click();
|
|
284
286
|
URL.revokeObjectURL(link.href);
|
|
285
|
-
console.log('Download CSV disparado no web');
|
|
286
287
|
return 'web-download';
|
|
287
|
-
} else {
|
|
288
|
-
throw new Error('FileSystem não disponível');
|
|
289
288
|
}
|
|
289
|
+
|
|
290
|
+
throw new Error('FileSystem não disponível');
|
|
290
291
|
} catch (err) {
|
|
291
292
|
console.error('Erro detalhado ao baixar CSV:', err);
|
|
292
293
|
throw new Error('Falha ao baixar o modelo CSV');
|
|
@@ -306,6 +307,7 @@ const Imports = ({ context = {}, onClose }) => {
|
|
|
306
307
|
<View style={styles.subHeader}>
|
|
307
308
|
<View style={styles.topRow}>
|
|
308
309
|
<View style={styles.topRowActions}>
|
|
310
|
+
{showCsvTemplate ? (
|
|
309
311
|
<TouchableOpacity style={styles.downloadButton} onPress={downloadTemplate}>
|
|
310
312
|
<View
|
|
311
313
|
style={{
|
|
@@ -323,6 +325,7 @@ const Imports = ({ context = {}, onClose }) => {
|
|
|
323
325
|
<Text style={[styles.downloadText, { color: buttonPalette.buttonText }]}>Baixar Modelo</Text>
|
|
324
326
|
</View>
|
|
325
327
|
</TouchableOpacity>
|
|
328
|
+
) : null}
|
|
326
329
|
|
|
327
330
|
<TouchableOpacity
|
|
328
331
|
style={[
|
|
@@ -397,16 +400,15 @@ const Imports = ({ context = {}, onClose }) => {
|
|
|
397
400
|
visible={showAddImportModal}
|
|
398
401
|
onClose={() => setShowAddImportModal(false)}
|
|
399
402
|
context={context}
|
|
403
|
+
importType={importType}
|
|
404
|
+
allowedExtensions={allowedExtensions}
|
|
400
405
|
onSuccess={() => {
|
|
401
406
|
setCurrentPage(1);
|
|
402
407
|
fetchImports(searchQuery, 1);
|
|
403
|
-
if (onImportComplete) onImportComplete();
|
|
404
408
|
}}
|
|
405
|
-
onImportComplete={onImportComplete}
|
|
406
409
|
/>
|
|
407
410
|
</View>
|
|
408
411
|
);
|
|
409
412
|
};
|
|
410
413
|
|
|
411
414
|
export default Imports;
|
|
412
|
-
// TODO(store-first): quando este arquivo for mexido, mover a leitura para stores, remover api.fetch e evitar repassar dados em objetos quando o store ja resolver isso.
|
|
@@ -23,6 +23,7 @@ const FileField = ({ field, value, editable, providerId, updateField }) => (
|
|
|
23
23
|
acceptedTypes={field.accept || '.pfx,.p12,application/x-pkcs12'}
|
|
24
24
|
fileType=""
|
|
25
25
|
fileTypeLabel="certificado"
|
|
26
|
+
knownFileIds={[extractFileId(value)].filter(Boolean)}
|
|
26
27
|
title={field.label}
|
|
27
28
|
triggerLabel="Gerenciar certificado"
|
|
28
29
|
managerTitle="Gerenciador de arquivos"
|
|
@@ -9,19 +9,20 @@ import useToastMessage from '@controleonline/ui-crm/src/react/hooks/useToastMess
|
|
|
9
9
|
import { useStore } from '@store';
|
|
10
10
|
import { colors } from '@controleonline/../../src/styles/colors';
|
|
11
11
|
import { resolveThemePalette, withOpacity } from '@controleonline/../../src/styles/branding';
|
|
12
|
-
import { getIntegrationConfig, getIntegrationByKey
|
|
12
|
+
import { getIntegrationConfig, getIntegrationByKey } from './integrationsCatalog';
|
|
13
|
+
import { fetchPeopleConfigs } from './fetchPeopleConfigs';
|
|
13
14
|
import IntegrationConfigFields from './IntegrationConfigFields';
|
|
14
15
|
import {
|
|
15
16
|
ROUTE_PROVIDER_MAP,
|
|
16
|
-
buildFieldValues,
|
|
17
17
|
extractAuthorizationUrl,
|
|
18
18
|
formatApiError,
|
|
19
19
|
formatUberOAuthError,
|
|
20
20
|
getConfigFields,
|
|
21
21
|
isConnectedValue,
|
|
22
|
+
isMethodNotAllowed,
|
|
23
|
+
mergeTabValues,
|
|
22
24
|
normalizeTextValue,
|
|
23
25
|
openAuthorizationUrl,
|
|
24
|
-
resolveFallbackConfigs,
|
|
25
26
|
resolveProviderId,
|
|
26
27
|
routeNameToPath,
|
|
27
28
|
toConfigRequestValue,
|
|
@@ -44,13 +45,13 @@ const CenterState = ({ icon, iconColor, title, text, backgroundColor, spinnerCol
|
|
|
44
45
|
</SafeAreaView>
|
|
45
46
|
);
|
|
46
47
|
|
|
47
|
-
export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
48
|
+
export default function IntegrationConfigPage({ route, embedded = false, fiscalTab = '', onlyFiscalTab = false }) {
|
|
48
49
|
const peopleStore = useStore('people');
|
|
49
50
|
const themeStore = useStore('theme');
|
|
50
51
|
const configsStore = useStore('configs');
|
|
51
52
|
const { currentCompany } = peopleStore.getters;
|
|
52
53
|
const { colors: themeColors } = themeStore.getters;
|
|
53
|
-
const configActions = configsStore.actions;
|
|
54
|
+
const configActions = configsStore.actions || {};
|
|
54
55
|
const { isSaving } = configsStore.getters;
|
|
55
56
|
const { showError, showSuccess } = useToastMessage();
|
|
56
57
|
const oauthNoticeRef = useRef('');
|
|
@@ -62,7 +63,8 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
62
63
|
const providerConfig = useMemo(() => getIntegrationConfig(providerKey), [providerKey]);
|
|
63
64
|
const configFields = useMemo(() => getConfigFields(providerConfig), [providerConfig]);
|
|
64
65
|
const fiscalTabs = providerConfig?.tabs || [];
|
|
65
|
-
const
|
|
66
|
+
const requestedFiscalTab = fiscalTab || route?.params?.fiscalTab || '';
|
|
67
|
+
const [activeFiscalTab, setActiveFiscalTab] = useState(() => requestedFiscalTab || fiscalTabs[0]?.key || 'general');
|
|
66
68
|
const activeTabDef = useMemo(
|
|
67
69
|
() => fiscalTabs.find(tab => tab.key === activeFiscalTab) || fiscalTabs[0] || null,
|
|
68
70
|
[activeFiscalTab, fiscalTabs],
|
|
@@ -71,10 +73,13 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
71
73
|
() => (activeTabDef?.fields?.length ? activeTabDef.fields : configFields),
|
|
72
74
|
[activeTabDef, configFields],
|
|
73
75
|
);
|
|
74
|
-
|
|
75
76
|
useEffect(() => {
|
|
77
|
+
if (requestedFiscalTab && fiscalTabs.some(tab => tab.key === requestedFiscalTab)) {
|
|
78
|
+
if (activeFiscalTab !== requestedFiscalTab) setActiveFiscalTab(requestedFiscalTab);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
76
81
|
if (fiscalTabs.length && !fiscalTabs.some(tab => tab.key === activeFiscalTab)) setActiveFiscalTab(fiscalTabs[0].key);
|
|
77
|
-
}, [activeFiscalTab, fiscalTabs]);
|
|
82
|
+
}, [activeFiscalTab, fiscalTabs, requestedFiscalTab]);
|
|
78
83
|
|
|
79
84
|
const returnPath = useMemo(() => {
|
|
80
85
|
const routePath = normalizeTextValue(route?.params?.return_path || route?.params?.returnPath || '');
|
|
@@ -88,28 +93,30 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
88
93
|
[themeColors, currentCompany?.id],
|
|
89
94
|
);
|
|
90
95
|
const [loading, setLoading] = useState(true);
|
|
96
|
+
const [tabLoading, setTabLoading] = useState(false);
|
|
91
97
|
const [refreshing, setRefreshing] = useState(false);
|
|
92
98
|
const [authLoading, setAuthLoading] = useState(false);
|
|
93
99
|
const [configValues, setConfigValues] = useState({});
|
|
94
100
|
const [integrationSummary, setIntegrationSummary] = useState(null);
|
|
95
101
|
|
|
96
|
-
// Company details can edit a company that is not the globally selected one.
|
|
97
|
-
// The embedded route id is authoritative for all fiscal reads and writes.
|
|
98
102
|
const providerId = useMemo(
|
|
99
|
-
() => resolveProviderId({ route, currentCompany }),
|
|
100
|
-
[route?.params?.companyId, currentCompany?.id],
|
|
103
|
+
() => resolveProviderId({ route, currentCompany, embedded }),
|
|
104
|
+
[embedded, route?.params?.companyId, route?.params?.clientId, currentCompany?.id],
|
|
101
105
|
);
|
|
102
106
|
const providerIri = useMemo(() => (providerId ? `/people/${providerId}` : ''), [providerId]);
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
const allConfigFields = useMemo(() => getConfigFields(providerConfig), [providerConfig]);
|
|
108
|
+
const allFieldKeys = useMemo(
|
|
109
|
+
() => allConfigFields.map(field => field.key).filter(Boolean),
|
|
110
|
+
[allConfigFields],
|
|
106
111
|
);
|
|
112
|
+
const allFieldKeysSig = useMemo(() => allFieldKeys.join('|'), [allFieldKeys]);
|
|
113
|
+
// Pure config providers (e.g. receita-federal) do not use marketplace/integrations.
|
|
114
|
+
const needsMarketplaceIntegration = Boolean(providerConfig?.oauthConnect);
|
|
107
115
|
|
|
108
|
-
|
|
109
|
-
setConfigValues(
|
|
110
|
-
}, [
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
setConfigValues({});
|
|
118
|
+
}, [providerIri]);
|
|
111
119
|
|
|
112
|
-
useEffect(() => syncConfigValues(fallbackConfigs), [fallbackConfigs, syncConfigValues]);
|
|
113
120
|
useEffect(() => {
|
|
114
121
|
const oauthStatus = normalizeTextValue(route?.params?.oauth_status).toLowerCase();
|
|
115
122
|
const oauthError = normalizeTextValue(route?.params?.oauth_error);
|
|
@@ -128,26 +135,49 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
128
135
|
}
|
|
129
136
|
if (showLoading) setLoading(true);
|
|
130
137
|
try {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
const keys = allFieldKeys.length
|
|
139
|
+
? allFieldKeys
|
|
140
|
+
: visibleFields.map(field => field.key).filter(Boolean);
|
|
141
|
+
|
|
142
|
+
if (keys.length) {
|
|
143
|
+
const configItems = await fetchPeopleConfigs({ peopleIri: providerIri, configKeys: keys });
|
|
144
|
+
const mergeFields = allConfigFields.length ? allConfigFields : visibleFields;
|
|
145
|
+
setConfigValues(current => mergeTabValues(mergeFields, configItems, current));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (needsMarketplaceIntegration) {
|
|
149
|
+
try {
|
|
150
|
+
const integrationResponse = await api.fetch('/marketplace/integrations', {
|
|
151
|
+
params: { provider_id: providerId },
|
|
152
|
+
});
|
|
153
|
+
setIntegrationSummary(getIntegrationByKey(integrationResponse, providerConfig.key));
|
|
154
|
+
} catch (integrationError) {
|
|
155
|
+
// OAuth / marketplace providers still surface the error; pure config never hits this branch.
|
|
156
|
+
showError(formatApiError(integrationError));
|
|
157
|
+
setIntegrationSummary(null);
|
|
158
|
+
}
|
|
139
159
|
} else {
|
|
140
|
-
setIntegrationSummary(
|
|
160
|
+
setIntegrationSummary(null);
|
|
141
161
|
}
|
|
142
162
|
} catch (error) {
|
|
143
163
|
showError(formatApiError(error));
|
|
144
|
-
syncConfigValues(fallbackConfigs);
|
|
145
164
|
setIntegrationSummary(null);
|
|
146
165
|
} finally {
|
|
147
|
-
|
|
166
|
+
setLoading(false);
|
|
167
|
+
setTabLoading(false);
|
|
148
168
|
}
|
|
149
|
-
}, [
|
|
169
|
+
}, [
|
|
170
|
+
allConfigFields,
|
|
171
|
+
allFieldKeys,
|
|
172
|
+
allFieldKeysSig,
|
|
173
|
+
needsMarketplaceIntegration,
|
|
174
|
+
providerConfig,
|
|
175
|
+
providerIri,
|
|
176
|
+
providerId,
|
|
177
|
+
showError,
|
|
178
|
+
]);
|
|
150
179
|
|
|
180
|
+
// Reload only when the company/provider identity or full key set changes — not on fiscal sub-tab switch.
|
|
151
181
|
useFocusEffect(useCallback(() => { loadPageData(); }, [loadPageData]));
|
|
152
182
|
const onRefresh = useCallback(async () => {
|
|
153
183
|
setRefreshing(true);
|
|
@@ -157,6 +187,29 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
157
187
|
setConfigValues(current => ({ ...current, [fieldKey]: value }));
|
|
158
188
|
}, []);
|
|
159
189
|
|
|
190
|
+
const persistConfigs = useCallback(async payload => {
|
|
191
|
+
if (typeof configActions.addManyConfigs === 'function') {
|
|
192
|
+
try {
|
|
193
|
+
return await configActions.addManyConfigs(payload);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (!isMethodNotAllowed(error)) throw error;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (typeof configActions.addConfigs !== 'function') {
|
|
199
|
+
throw new Error('Nao foi possivel salvar: acao de configs indisponivel.');
|
|
200
|
+
}
|
|
201
|
+
for (const item of payload.configs) {
|
|
202
|
+
await configActions.addConfigs({
|
|
203
|
+
configKey: item.configKey,
|
|
204
|
+
configValue: item.configValue,
|
|
205
|
+
people: payload.people,
|
|
206
|
+
module: payload.module,
|
|
207
|
+
visibility: payload.visibility,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}, [configActions]);
|
|
212
|
+
|
|
160
213
|
const handleOAuthConnect = useCallback(async () => {
|
|
161
214
|
if (!providerIri || !providerConfig?.oauthConnect) {
|
|
162
215
|
showError('Nao foi possivel identificar a integracao selecionada.');
|
|
@@ -181,29 +234,32 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
181
234
|
? isConnectedValue(integrationSummary.connected)
|
|
182
235
|
: requiredKeys.length > 0 && requiredKeys.every(key => normalizeTextValue(configValues[key]) !== '');
|
|
183
236
|
const statusTone = connected ? '#16A34A' : '#e67e22';
|
|
184
|
-
const editable = Boolean(providerIri && providerConfig && !
|
|
185
|
-
const actionLoading = providerConfig?.oauthConnect ? authLoading : isSaving;
|
|
186
|
-
const actionDisabled = providerConfig?.oauthConnect ? authLoading || loading : !editable;
|
|
237
|
+
const editable = Boolean(providerIri && providerConfig && !providerConfig.oauthConnect);
|
|
238
|
+
const actionLoading = providerConfig?.oauthConnect ? authLoading : Boolean(isSaving || tabLoading);
|
|
239
|
+
const actionDisabled = providerConfig?.oauthConnect ? authLoading || loading : !editable || actionLoading;
|
|
240
|
+
const saveLabel = fiscalTabs.length
|
|
241
|
+
? `Salvar ${activeTabDef?.label || 'aba'}`
|
|
242
|
+
: providerConfig?.saveLabel;
|
|
187
243
|
|
|
188
244
|
const saveIntegration = useCallback(async () => {
|
|
189
245
|
if (!providerIri || !providerConfig || providerConfig.oauthConnect) {
|
|
190
246
|
showError('Nao foi possivel identificar a integracao selecionada.');
|
|
191
247
|
return;
|
|
192
248
|
}
|
|
193
|
-
const configs =
|
|
249
|
+
const configs = visibleFields.map(field => ({
|
|
194
250
|
configKey: field.key,
|
|
195
251
|
configValue: toConfigRequestValue(normalizeTextValue(configValues[field.key])),
|
|
196
252
|
}));
|
|
197
253
|
try {
|
|
198
|
-
await
|
|
199
|
-
showSuccess(`${providerConfig.label} salvo com sucesso.`);
|
|
254
|
+
await persistConfigs({ configs, people: providerIri, module: 4, visibility: 'public' });
|
|
255
|
+
showSuccess(`${activeTabDef?.label || providerConfig.label} salvo com sucesso.`);
|
|
200
256
|
await loadPageData({ showLoading: false });
|
|
201
257
|
} catch (error) { showError(error?.message || 'Nao foi possivel salvar a integracao.'); }
|
|
202
|
-
}, [
|
|
258
|
+
}, [activeTabDef, configValues, loadPageData, persistConfigs, providerConfig, providerIri, showError, showSuccess, visibleFields]);
|
|
203
259
|
|
|
204
260
|
if (!providerConfig) return <CenterState icon="alert-triangle" iconColor="#e67e22" title="Integracao indisponivel" text="A tela solicitada nao possui configuracao cadastrada." />;
|
|
205
|
-
if (!providerId) return <CenterState icon="building" iconColor="#94A3B8" title="
|
|
206
|
-
if (loading) return <CenterState backgroundColor={brandColors.background} spinnerColor={providerConfig.accent} title="Carregando integracao" text="Buscando as credenciais
|
|
261
|
+
if (!providerId) return <CenterState icon="building" iconColor="#94A3B8" title="Empresa nao identificada" text="Abra a ficha da empresa para gravar as configuracoes fiscais nela." />;
|
|
262
|
+
if (loading) return <CenterState backgroundColor={brandColors.background} spinnerColor={providerConfig.accent} title="Carregando integracao" text="Buscando as credenciais desta aba." />;
|
|
207
263
|
|
|
208
264
|
return (
|
|
209
265
|
<SafeAreaView style={[styles.container, { backgroundColor: brandColors.background }]} edges={['bottom']}>
|
|
@@ -227,7 +283,7 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
227
283
|
<Text style={styles.sectionTitle}>Status</Text>
|
|
228
284
|
<Text style={styles.sectionSubtitle}>{providerConfig.oauthConnect
|
|
229
285
|
? 'A integracao fica conectada quando o login do Uber termina e o store e salvo automaticamente.'
|
|
230
|
-
: 'A integracao so aparece como conectada quando todos os campos obrigatorios foram salvos
|
|
286
|
+
: 'A integracao so aparece como conectada quando todos os campos obrigatorios foram salvos nesta empresa.'}</Text>
|
|
231
287
|
</View>
|
|
232
288
|
<View style={[styles.statusBadge, { backgroundColor: withOpacity(statusTone, 0.12) }]}>
|
|
233
289
|
<Text style={[styles.statusBadgeText, { color: statusTone }]}>{connected ? 'Conectado' : 'Pendente'}</Text>
|
|
@@ -240,7 +296,7 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
240
296
|
<Text style={styles.cardTitle}>{providerConfig.oauthConnect ? 'Conexao' : fiscalTabs.length ? activeTabDef?.label || 'Configuracoes' : 'Credenciais'}</Text>
|
|
241
297
|
{!embedded ? <Text style={styles.cardSubtitle}>{providerConfig.oauthConnect
|
|
242
298
|
? 'Use o login oficial do Uber. A store sera localizada e gravada automaticamente na empresa ativa.'
|
|
243
|
-
: '
|
|
299
|
+
: 'Troca de aba e local; as configuracoes sao carregadas uma vez e cada aba grava so as chaves dela.'}</Text> : null}
|
|
244
300
|
|
|
245
301
|
{providerConfig.oauthConnect ? (
|
|
246
302
|
<View style={styles.fieldList}><View style={styles.fieldGroup}>
|
|
@@ -249,7 +305,7 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
249
305
|
</View></View>
|
|
250
306
|
) : (
|
|
251
307
|
<View style={styles.fieldList}>
|
|
252
|
-
{fiscalTabs.length ? <View style={styles.subTabRow}>{fiscalTabs.map(tab => {
|
|
308
|
+
{fiscalTabs.length && !onlyFiscalTab ? <View style={styles.subTabRow}>{fiscalTabs.map(tab => {
|
|
253
309
|
const selected = tab.key === (activeTabDef?.key || activeFiscalTab);
|
|
254
310
|
return <TouchableOpacity key={tab.key} style={[styles.subTabButton, selected && styles.subTabButtonActive]}
|
|
255
311
|
activeOpacity={0.85} onPress={() => setActiveFiscalTab(tab.key)}>
|
|
@@ -257,6 +313,7 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
257
313
|
</TouchableOpacity>;
|
|
258
314
|
})}</View> : null}
|
|
259
315
|
{activeTabDef?.description ? <Text style={styles.tabDescription}>{activeTabDef.description}</Text> : null}
|
|
316
|
+
{tabLoading ? <ActivityIndicator color={providerConfig.accent} /> : null}
|
|
260
317
|
<IntegrationConfigFields fields={visibleFields} configValues={configValues} editable={editable}
|
|
261
318
|
embedded={embedded} providerId={providerId} updateField={updateField} />
|
|
262
319
|
</View>
|
|
@@ -265,11 +322,10 @@ export default function IntegrationConfigPage({ route, embedded = false }) {
|
|
|
265
322
|
<TouchableOpacity style={[styles.saveButton, { backgroundColor: providerConfig.accent }, actionDisabled && styles.saveButtonDisabled]}
|
|
266
323
|
disabled={actionDisabled} activeOpacity={0.9} onPress={providerConfig.oauthConnect ? handleOAuthConnect : saveIntegration}>
|
|
267
324
|
{actionLoading ? <ActivityIndicator color="#FFFFFF" /> : <Icon name={providerConfig.oauthConnect ? 'log-in' : 'save'} size={16} color="#FFFFFF" />}
|
|
268
|
-
<Text style={styles.saveButtonText}>{providerConfig.oauthConnect ? providerConfig.connectLabel || 'Conectar' :
|
|
325
|
+
<Text style={styles.saveButtonText}>{providerConfig.oauthConnect ? providerConfig.connectLabel || 'Conectar' : saveLabel}</Text>
|
|
269
326
|
</TouchableOpacity>
|
|
270
327
|
</View>
|
|
271
328
|
</ScrollView>
|
|
272
329
|
</SafeAreaView>
|
|
273
330
|
);
|
|
274
331
|
}
|
|
275
|
-
// TODO(store-first): quando este arquivo for mexido, mover a leitura para stores, remover api.fetch e evitar repassar dados em objetos quando o store ja resolver isso.
|
|
@@ -35,7 +35,7 @@ export const getConfigFields = providerConfig => {
|
|
|
35
35
|
return providerConfig.fields || [];
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
export const
|
|
38
|
+
export const mergeTabValues = (fields, source, current = {}) => {
|
|
39
39
|
const sourceMap = Array.isArray(source)
|
|
40
40
|
? source.reduce((acc, item) => {
|
|
41
41
|
const key = String(item?.configKey || '').trim();
|
|
@@ -44,23 +44,25 @@ export const buildFieldValues = (providerConfig, source) => {
|
|
|
44
44
|
}, {})
|
|
45
45
|
: source && typeof source === 'object' ? source : {};
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const next = { ...current };
|
|
48
|
+
(fields || []).forEach(field => {
|
|
49
|
+
next[field.key] = Object.prototype.hasOwnProperty.call(sourceMap, field.key)
|
|
50
|
+
? normalizeTextValue(sourceMap[field.key])
|
|
51
|
+
: normalizeTextValue(next[field.key]);
|
|
52
|
+
});
|
|
53
|
+
return next;
|
|
51
54
|
};
|
|
52
55
|
|
|
53
|
-
export const
|
|
54
|
-
|
|
55
|
-
if (routeCompanyId) return Number(routeCompanyId);
|
|
56
|
+
export const buildFieldValues = (providerConfig, source) =>
|
|
57
|
+
mergeTabValues(getConfigFields(providerConfig), source, {});
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
export const resolveProviderId = ({ route, currentCompany, embedded = false }) => {
|
|
60
|
+
const fromRoute = String(route?.params?.companyId || route?.params?.clientId || '').replace(/\D/g, '');
|
|
61
|
+
if (fromRoute) return fromRoute;
|
|
62
|
+
if (embedded) return '';
|
|
63
|
+
return String(currentCompany?.id || '').replace(/\D/g, '');
|
|
59
64
|
};
|
|
60
65
|
|
|
61
|
-
export const resolveFallbackConfigs = ({ providerId, currentCompany }) =>
|
|
62
|
-
Number(providerId) === Number(currentCompany?.id) ? currentCompany?.configs || {} : {};
|
|
63
|
-
|
|
64
66
|
export const isConnectedValue = value =>
|
|
65
67
|
value === true || value === 1 || value === '1' || String(value).trim().toLowerCase() === 'true';
|
|
66
68
|
|
|
@@ -93,3 +95,9 @@ export const openAuthorizationUrl = async authUrl => {
|
|
|
93
95
|
}
|
|
94
96
|
await Linking.openURL(authUrl);
|
|
95
97
|
};
|
|
98
|
+
|
|
99
|
+
export const isMethodNotAllowed = error => {
|
|
100
|
+
const status = Number(error?.status || error?.code || error?.body?.status || 0);
|
|
101
|
+
const message = String(error?.message || '').toLowerCase();
|
|
102
|
+
return status === 404 || status === 405 || message.includes('method not allowed');
|
|
103
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { api } from '@controleonline/ui-common/src/api';
|
|
2
|
+
import { parseIntegrationCollection } from './integrationsCatalog';
|
|
3
|
+
|
|
4
|
+
export async function fetchPeopleConfigs({ peopleIri, configKeys = [] }) {
|
|
5
|
+
const keys = [...new Set(configKeys.map(key => String(key || '').trim()).filter(Boolean))];
|
|
6
|
+
if (!peopleIri || !keys.length) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const response = await api.fetch('/configs', {
|
|
11
|
+
params: {
|
|
12
|
+
people: peopleIri,
|
|
13
|
+
configKey: keys,
|
|
14
|
+
itemsPerPage: keys.length,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return parseIntegrationCollection(response).filter(item =>
|
|
19
|
+
keys.includes(String(item?.configKey || '').trim()),
|
|
20
|
+
);
|
|
21
|
+
}
|