@controleonline/ui-common 1.2.70 → 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.
- package/.github/actions/workers/manager/action.yml +147 -0
- package/.github/actions/workers/qa/action.yml +44 -0
- package/.github/actions/workers/security/action.yml +44 -0
- package/.github/actions/workers/technical-documenter/action.yml +51 -0
- package/.github/workflows/manager-worker.yml +168 -0
- package/.github/workflows/publish-npm.yml +45 -0
- package/.gitmodules +3 -0
- package/AGENTS.md +6 -0
- package/README.md +14 -0
- package/package.json +32 -28
- package/src/api/fetch.js +1 -1
- package/src/api/index.js +328 -58
- package/src/react/components/AddImportModal.js +95 -111
- package/src/react/components/AnimatedModal.js +171 -0
- package/src/react/components/AnimatedModal.styles.js +21 -0
- package/src/react/components/AppTypeSwitcher.js +164 -0
- package/src/react/components/AppTypeSwitcher.styles.js +109 -0
- package/src/react/components/BackgroundRuntimeBridge.js +5 -4
- package/src/react/components/BottomNavigationBar.config.js +211 -231
- package/src/react/components/BottomNavigationBar.js +86 -31
- package/src/react/components/BottomNavigationBar.styles.js +118 -110
- package/src/react/components/CategoryForm.js +52 -35
- package/src/react/components/DefaultProvider.native.js +194 -156
- package/src/react/components/DefaultProvider.web.js +188 -112
- package/src/react/components/DeliveryPushBridge.native.js +2 -2
- package/src/react/components/DeviceAlertSoundService.js +3 -3
- package/src/react/components/KioskModeBridge.js +2 -2
- package/src/react/components/LauncherModeBridge.js +2 -2
- package/src/react/components/ManagerPushBridge.native.js +2 -2
- package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
- package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
- package/src/react/components/RemoteCheckoutService.js +28 -20
- package/src/react/components/RuntimeBottomNavigationBar.js +146 -119
- package/src/react/components/RuntimeInfoFooter.js +137 -45
- package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
- package/src/react/components/StateStore.js +258 -0
- package/src/react/components/UnifiedPaymentBar.js +7 -4
- package/src/react/components/UserAvatar.js +160 -0
- package/src/react/components/WebsocketListener.native.js +11 -11
- package/src/react/components/integrations/IntegrationHero/index.js +48 -0
- package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
- package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
- package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
- package/src/react/config/deviceConfigBootstrap.js +71 -30
- package/src/react/css/orders.js +72 -0
- package/src/react/pages/Connections.js +229 -0
- package/src/react/pages/Connections.styles.js +222 -0
- package/src/react/pages/DeviceDetailPage.js +2814 -0
- package/src/react/pages/DeviceDetailPage.styles.js +308 -0
- package/src/react/pages/Devices/currentDevice.js +194 -0
- package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
- package/src/react/pages/Devices/deviceTypes/all.js +23 -0
- package/src/react/pages/Devices/deviceTypes/device.js +25 -0
- package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
- package/src/react/pages/Devices/deviceTypes/display.js +26 -0
- package/src/react/pages/Devices/deviceTypes/index.js +145 -0
- package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
- package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
- package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
- package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
- package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
- package/src/react/pages/Devices.js +183 -0
- package/src/react/pages/Devices.styles.js +353 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
- package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
- package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
- package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
- package/src/react/pages/Food99IntegrationPage.js +1 -0
- package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
- package/src/react/pages/GenericLogPage.js +42 -167
- package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
- package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
- package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
- package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
- package/src/react/pages/IFoodIntegrationPage.js +1 -0
- package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
- package/src/react/pages/Imports.js +214 -166
- package/src/react/pages/IntegrationConfigPage.js +744 -0
- package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
- package/src/react/pages/Integrations.js +299 -0
- package/src/react/pages/Integrations.styles.js +130 -0
- package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
- package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
- package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
- package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
- package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
- package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
- package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
- package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
- package/src/react/pages/PrinterDeviceFormPage.js +521 -0
- package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
- package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +484 -454
- package/src/react/pages/SettingsPage/index.js +1266 -1167
- package/src/react/pages/WhatsAppConnectionPage.js +459 -0
- package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
- package/src/react/pages/integrationsCatalog.js +399 -0
- package/src/react/print/providers/local.js +1 -1
- package/src/react/router/publicRoutes.js +25 -0
- package/src/react/services/Cielo/Checkout.js +39 -0
- package/src/react/services/Cielo/Cielo.js +193 -0
- package/src/react/services/Cielo/Print.js +7 -0
- package/src/react/services/InfinitePay/Checkout.js +33 -0
- package/src/react/services/InfinitePay/InfinitePay.js +24 -0
- package/src/react/{utils → services}/paymentGatewayExecution.js +91 -91
- package/src/react/styles/global.js +115 -0
- package/src/react/utils/categoryContexts.js +46 -0
- package/src/react/utils/entityDisplay.js +222 -217
- package/src/react/utils/fileUrl.js +201 -16
- package/src/react/utils/integrationPage.js +16 -0
- package/src/react/utils/menuNavigation.js +31 -0
- package/src/react/utils/orderIdentity.js +277 -0
- package/src/react/utils/remotePayment.js +115 -61
- package/src/react/utils/runtimeFooter.js +40 -22
- package/src/react/utils/runtimeLanguage.js +50 -9
- package/src/react/utils/runtimeMenu.js +190 -98
- package/src/react/utils/runtimeZoom.js +43 -0
- package/src/react/utils/shopConfig.js +72 -34
- package/src/react/utils/shopFranchises.js +182 -23
- package/src/react/utils/socketRuntimePipeline.js +14 -14
- package/src/react/utils/storeColumns.js +23 -4
- package/src/react/utils/userAvatar.js +104 -0
- package/src/store/categories/index.js +48 -20
- package/src/store/configs/index.js +2 -2
- package/src/store/device_config/index.js +62 -21
- package/src/store/entity_log/index.js +22 -1
- package/src/store/imports/customActions.js +51 -0
- package/src/store/imports/index.js +89 -88
- package/src/store/status/index.js +11 -11
- package/src/store/themes/index.js +22 -0
- package/src/store/timezones/index.js +3 -1
- package/src/tests/browser/manager/connections.spec.js +143 -0
- package/src/tests/browser/manager/devices-current.spec.js +343 -0
- package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
- package/src/tests/react/api/deviceHeaders.test.js +114 -0
- package/src/tests/react/api/loadSmokeIndex.test.js +75 -0
- package/src/tests/react/components/AddImportModal.test.js +166 -0
- package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
- package/src/tests/react/components/UserAvatar.test.js +52 -0
- package/src/tests/react/config/deviceConfigBootstrap.test.js +47 -0
- package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
- package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
- package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
- package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
- package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
- package/src/tests/react/print/localPrintProvider.test.js +1 -1
- package/src/tests/react/services/Cielo.test.js +190 -0
- package/src/tests/react/store/categoriesOrdering.test.js +26 -0
- package/src/tests/react/utils/appDomain.test.js +62 -0
- package/src/tests/react/utils/entityDisplay.test.js +2 -2
- package/src/tests/react/utils/fileUrl.test.js +62 -0
- package/src/tests/react/utils/formatter.test.mjs +33 -0
- package/src/tests/react/utils/importStatus.test.js +2 -2
- package/src/tests/react/utils/orderIdentity.test.js +139 -0
- package/src/tests/react/utils/remotePayment.test.js +62 -0
- package/src/tests/react/utils/runtimeFooter.test.js +32 -9
- package/src/tests/react/utils/runtimeLanguage.test.js +80 -10
- package/src/tests/react/utils/runtimeMenu.test.js +195 -111
- package/src/tests/react/utils/runtimeZoom.test.js +38 -0
- package/src/tests/react/utils/shopConfig.test.js +75 -0
- package/src/tests/react/utils/shopFranchises.test.js +122 -12
- package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
- package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
- package/src/tests/react/utils/translate.test.mjs +252 -396
- package/src/tests/react/utils/userAvatar.test.js +63 -0
- package/src/utils/appDomain.js +15 -4
- package/src/utils/formatter.js +122 -16
- package/src/utils/integrationConfigs.js +1 -0
- package/src/utils/translate.js +277 -398
- package/src/utils/translateDiscovery.js +96 -0
- package/src/utils/translateNormalize.js +33 -0
- package/src/utils/translatePending.js +92 -0
- package/src/utils/translateStorage.js +142 -0
- package/.github/agents/developer.agent.md +0 -30
- package/.github/agents/devops.agent.md +0 -30
- package/.github/agents/qa.agent.md +0 -30
- package/.github/agents/security.agent.md +0 -30
- package/.github/workflows/npmjs.yml +0 -35
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {env as APP_ENV} from '@env';
|
|
2
|
+
import {buildAssetUrl} from '@controleonline/../../src/styles/branding';
|
|
3
3
|
import {
|
|
4
4
|
resolveAppDomain,
|
|
5
5
|
resolveCompanyDomain,
|
|
6
6
|
} from '@controleonline/ui-common/src/utils/appDomain';
|
|
7
7
|
|
|
8
8
|
const IMAGE_PATH_PATTERN = /\.(?:avif|bmp|gif|ico|jpe?g|png|svg|webp)(?:\?|$)/i;
|
|
9
|
+
const FILE_DOWNLOAD_PATTERN = /(?:^|\/)files\/[^/?#]+\/download(?:[?#]|$)/i;
|
|
9
10
|
|
|
10
11
|
const normalizeText = value => String(value || '').trim();
|
|
11
12
|
|
|
@@ -21,6 +22,107 @@ const unwrapFile = file => {
|
|
|
21
22
|
return file;
|
|
22
23
|
};
|
|
23
24
|
|
|
25
|
+
const isDownloadLikeUrl = value =>
|
|
26
|
+
FILE_DOWNLOAD_PATTERN.test(normalizeText(value));
|
|
27
|
+
|
|
28
|
+
const stripDomainQueryParams = url => {
|
|
29
|
+
const normalizedUrl = normalizeText(url);
|
|
30
|
+
if (!normalizedUrl) {
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const hashIndex = normalizedUrl.indexOf('#');
|
|
35
|
+
const hash = hashIndex >= 0 ? normalizedUrl.slice(hashIndex) : '';
|
|
36
|
+
const urlWithoutHash =
|
|
37
|
+
hashIndex >= 0 ? normalizedUrl.slice(0, hashIndex) : normalizedUrl;
|
|
38
|
+
const queryIndex = urlWithoutHash.indexOf('?');
|
|
39
|
+
const base =
|
|
40
|
+
queryIndex >= 0 ? urlWithoutHash.slice(0, queryIndex) : urlWithoutHash;
|
|
41
|
+
const query = queryIndex >= 0 ? urlWithoutHash.slice(queryIndex + 1) : '';
|
|
42
|
+
const params = query
|
|
43
|
+
? query
|
|
44
|
+
.split('&')
|
|
45
|
+
.map(item => item.trim())
|
|
46
|
+
.filter(Boolean)
|
|
47
|
+
.filter(item => {
|
|
48
|
+
const [rawKey] = item.split('=');
|
|
49
|
+
const key = decodeURIComponent(rawKey || '').toLowerCase();
|
|
50
|
+
return key !== 'app-domain' && key !== 'appdomain';
|
|
51
|
+
})
|
|
52
|
+
: [];
|
|
53
|
+
|
|
54
|
+
return `${base}${params.length ? `?${params.join('&')}` : ''}${hash}`;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const ensureAbsoluteUrl = url => {
|
|
58
|
+
const normalizedUrl = normalizeText(url);
|
|
59
|
+
if (!normalizedUrl) {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (/^https?:\/\//i.test(normalizedUrl) || /^\/\//.test(normalizedUrl)) {
|
|
64
|
+
return buildAssetUrl(normalizedUrl) || normalizedUrl;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const apiEntryPoint = normalizeText(APP_ENV?.API_ENTRYPOINT).replace(
|
|
68
|
+
/\/$/,
|
|
69
|
+
'',
|
|
70
|
+
);
|
|
71
|
+
const normalizedPath = normalizedUrl.startsWith('/')
|
|
72
|
+
? normalizedUrl
|
|
73
|
+
: `/${normalizedUrl}`;
|
|
74
|
+
|
|
75
|
+
return apiEntryPoint ? `${apiEntryPoint}${normalizedPath}` : normalizedPath;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const resolveDownloadHost = ({company = null, appDomain = ''} = {}) => {
|
|
79
|
+
const fallbackDomain =
|
|
80
|
+
normalizeText(appDomain) || resolveAppDomain(APP_ENV?.DOMAIN);
|
|
81
|
+
return resolveCompanyDomain(company, fallbackDomain);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const buildBackendDownloadUrl = (fileId, options = {}) => {
|
|
85
|
+
const normalizedId = String(fileId || '').trim();
|
|
86
|
+
if (!normalizedId) {
|
|
87
|
+
return '';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const host = resolveDownloadHost(options);
|
|
91
|
+
const relativeUrl = `/files/${normalizedId}/download`;
|
|
92
|
+
|
|
93
|
+
return buildTenantDownloadUrl(relativeUrl, host);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const buildTenantDownloadUrl = (url, host) => {
|
|
97
|
+
const absoluteUrl = ensureAbsoluteUrl(stripDomainQueryParams(url));
|
|
98
|
+
const normalizedHost = normalizeText(host);
|
|
99
|
+
if (!absoluteUrl || !normalizedHost) {
|
|
100
|
+
return absoluteUrl;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (/^https?:\/\//i.test(absoluteUrl)) {
|
|
104
|
+
const match = stripDomainQueryParams(absoluteUrl).match(
|
|
105
|
+
/^(https?:\/\/[^/?#]+)\/(?:[^/]+\/)?files\/([^/?#]+)\/download([^#]*)(#.*)?$/i,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return match
|
|
109
|
+
? `${match[1]}/${encodeURIComponent(normalizedHost)}/files/${match[2]}/download${match[3] || ''}${match[4] || ''}`
|
|
110
|
+
: stripDomainQueryParams(absoluteUrl);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const hashIndex = absoluteUrl.indexOf('#');
|
|
114
|
+
const hash = hashIndex >= 0 ? absoluteUrl.slice(hashIndex) : '';
|
|
115
|
+
const urlWithoutHash = hashIndex >= 0 ? absoluteUrl.slice(0, hashIndex) : absoluteUrl;
|
|
116
|
+
const queryIndex = urlWithoutHash.indexOf('?');
|
|
117
|
+
const path = queryIndex >= 0 ? urlWithoutHash.slice(0, queryIndex) : urlWithoutHash;
|
|
118
|
+
const query = queryIndex >= 0 ? urlWithoutHash.slice(queryIndex) : '';
|
|
119
|
+
const match = path.match(/^\/(?:[^/]+\/)?files\/([^/]+)\/download$/i);
|
|
120
|
+
|
|
121
|
+
return match
|
|
122
|
+
? `/${encodeURIComponent(normalizedHost)}/files/${match[1]}/download${query}${hash}`
|
|
123
|
+
: stripDomainQueryParams(absoluteUrl);
|
|
124
|
+
};
|
|
125
|
+
|
|
24
126
|
const resolveDirectFileUrl = file => {
|
|
25
127
|
if (!file) {
|
|
26
128
|
return '';
|
|
@@ -77,26 +179,109 @@ export const extractFileId = file => {
|
|
|
77
179
|
return null;
|
|
78
180
|
};
|
|
79
181
|
|
|
80
|
-
|
|
81
|
-
|
|
182
|
+
export const resolveDefaultFileSource = (
|
|
183
|
+
file,
|
|
184
|
+
{company = null, appDomain = '', headers = {}} = {},
|
|
185
|
+
) => {
|
|
82
186
|
const normalizedFile = unwrapFile(file);
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
187
|
+
const host = resolveDownloadHost({company, appDomain});
|
|
188
|
+
|
|
189
|
+
if (!normalizedFile) {
|
|
190
|
+
return null;
|
|
86
191
|
}
|
|
87
192
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
193
|
+
if (typeof normalizedFile === 'number') {
|
|
194
|
+
const uri = buildBackendDownloadUrl(normalizedFile, {company, appDomain});
|
|
195
|
+
|
|
196
|
+
return uri
|
|
197
|
+
? {
|
|
198
|
+
uri,
|
|
199
|
+
headers: host ? {...headers, 'app-domain': host} : {...headers},
|
|
200
|
+
}
|
|
201
|
+
: null;
|
|
91
202
|
}
|
|
92
203
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
204
|
+
if (typeof normalizedFile === 'string') {
|
|
205
|
+
const normalizedValue = normalizeText(normalizedFile);
|
|
206
|
+
if (!normalizedValue) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
98
209
|
|
|
99
|
-
|
|
210
|
+
if (isDownloadLikeUrl(normalizedValue)) {
|
|
211
|
+
const uri = buildTenantDownloadUrl(normalizedValue, host);
|
|
212
|
+
|
|
213
|
+
return uri
|
|
214
|
+
? {
|
|
215
|
+
uri,
|
|
216
|
+
headers: host ? {...headers, 'app-domain': host} : {...headers},
|
|
217
|
+
}
|
|
218
|
+
: null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const numericId = extractFileId(normalizedValue);
|
|
222
|
+
if (numericId && !IMAGE_PATH_PATTERN.test(normalizedValue)) {
|
|
223
|
+
const uri = buildBackendDownloadUrl(numericId, {company, appDomain});
|
|
224
|
+
|
|
225
|
+
return uri
|
|
226
|
+
? {
|
|
227
|
+
uri,
|
|
228
|
+
headers: host ? {...headers, 'app-domain': host} : {...headers},
|
|
229
|
+
}
|
|
230
|
+
: null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const directUrl = resolveDirectFileUrl(normalizedValue);
|
|
234
|
+
|
|
235
|
+
return directUrl
|
|
236
|
+
? {
|
|
237
|
+
uri: directUrl,
|
|
238
|
+
headers: {...headers},
|
|
239
|
+
}
|
|
240
|
+
: null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (typeof normalizedFile === 'object' && !Array.isArray(normalizedFile)) {
|
|
244
|
+
const sourceHeaders =
|
|
245
|
+
normalizedFile?.headers && typeof normalizedFile.headers === 'object'
|
|
246
|
+
? normalizedFile.headers
|
|
247
|
+
: {};
|
|
248
|
+
const fileId = extractFileId(normalizedFile);
|
|
249
|
+
const directUrl = resolveDirectFileUrl(normalizedFile);
|
|
250
|
+
const isBackendDownload =
|
|
251
|
+
Boolean(fileId) ||
|
|
252
|
+
isDownloadLikeUrl(directUrl) ||
|
|
253
|
+
isDownloadLikeUrl(normalizedFile?.uri) ||
|
|
254
|
+
isDownloadLikeUrl(normalizedFile?.url) ||
|
|
255
|
+
isDownloadLikeUrl(normalizedFile?.path);
|
|
256
|
+
const uriBase =
|
|
257
|
+
directUrl ||
|
|
258
|
+
(fileId ? buildBackendDownloadUrl(fileId, {company, appDomain}) : '');
|
|
259
|
+
|
|
260
|
+
if (!uriBase) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const uri = isBackendDownload
|
|
265
|
+
? buildTenantDownloadUrl(uriBase, host)
|
|
266
|
+
: uriBase;
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
uri,
|
|
270
|
+
headers:
|
|
271
|
+
isBackendDownload && host
|
|
272
|
+
? {...sourceHeaders, ...headers, 'app-domain': host}
|
|
273
|
+
: {...sourceHeaders, ...headers},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return null;
|
|
100
278
|
};
|
|
101
279
|
|
|
280
|
+
export const resolveDefaultFileUrl = (file, options = {}) =>
|
|
281
|
+
resolveDefaultFileSource(file, options)?.uri || '';
|
|
282
|
+
|
|
283
|
+
// Centraliza a resolucao de imagem/arquivo do backend em uma unica regra.
|
|
284
|
+
export const resolveFileImageUrl = (file, options = {}) =>
|
|
285
|
+
resolveDefaultFileUrl(file, options);
|
|
286
|
+
|
|
102
287
|
export const resolveFileDownloadUrl = resolveFileImageUrl;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
// Sombra base reutilizada em cards das telas de integração.
|
|
4
|
+
export const integrationCardShadowStyle = Platform.select({
|
|
5
|
+
ios: {
|
|
6
|
+
shadowColor: '#0F172A',
|
|
7
|
+
shadowOffset: { width: 0, height: 8 },
|
|
8
|
+
shadowOpacity: 0.08,
|
|
9
|
+
shadowRadius: 16,
|
|
10
|
+
},
|
|
11
|
+
android: { elevation: 3 },
|
|
12
|
+
web: { boxShadow: '0 10px 24px rgba(15,23,42,0.08)' },
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Contagem defensiva para listas usadas em resumos e pré-visualizações.
|
|
16
|
+
export const countCollection = collection => (Array.isArray(collection) ? collection.length : 0);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const LEGACY_ROUTE_ALIASES = {
|
|
2
|
+
displayList: 'DisplayList',
|
|
3
|
+
displayDetails: 'DisplayDetails',
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export const resolveMenuRouteName = routeName => {
|
|
7
|
+
const normalizedRouteName = String(routeName || '').trim();
|
|
8
|
+
|
|
9
|
+
if (!normalizedRouteName) {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return LEGACY_ROUTE_ALIASES[normalizedRouteName] || normalizedRouteName;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const resolveMenuRouteParams = routeParams => {
|
|
17
|
+
if (
|
|
18
|
+
routeParams &&
|
|
19
|
+
typeof routeParams === 'object' &&
|
|
20
|
+
!Array.isArray(routeParams)
|
|
21
|
+
) {
|
|
22
|
+
return routeParams;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
resolveMenuRouteName,
|
|
30
|
+
resolveMenuRouteParams,
|
|
31
|
+
};
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Regra de negocio: a identidade operacional nao pode inventar codigo de
|
|
3
|
+
* marketplace. O resolvedor usa apenas campos canonicos do pedido.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const normalizeText = value => String(value ?? '').trim();
|
|
7
|
+
|
|
8
|
+
const normalizeKey = value =>
|
|
9
|
+
normalizeText(value)
|
|
10
|
+
.normalize('NFD')
|
|
11
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
12
|
+
.toLowerCase();
|
|
13
|
+
|
|
14
|
+
const formatOrderCode = value => {
|
|
15
|
+
const normalized = normalizeText(value);
|
|
16
|
+
return normalized ? `#${normalized}` : '';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const isObject = value =>
|
|
20
|
+
value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
21
|
+
|
|
22
|
+
const parseJsonObject = value => {
|
|
23
|
+
if (isObject(value)) {
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (typeof value !== 'string') {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const parsed = JSON.parse(value);
|
|
33
|
+
if (typeof parsed === 'string') {
|
|
34
|
+
return parseJsonObject(parsed);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return isObject(parsed) ? parsed : {};
|
|
38
|
+
} catch {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const getExtraDataList = order => {
|
|
44
|
+
if (Array.isArray(order?.extraData)) {
|
|
45
|
+
return order.extraData;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (Array.isArray(order?.extra_data)) {
|
|
49
|
+
return order.extra_data;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return [];
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const getExtraDataMap = order =>
|
|
56
|
+
getExtraDataList(order).reduce((currentMap, extraData) => {
|
|
57
|
+
const context = normalizeKey(
|
|
58
|
+
extraData?.extra_fields?.context || extraData?.extraFields?.context,
|
|
59
|
+
);
|
|
60
|
+
const name = normalizeText(
|
|
61
|
+
extraData?.extra_fields?.name || extraData?.extraFields?.name,
|
|
62
|
+
);
|
|
63
|
+
const value = normalizeText(extraData?.value);
|
|
64
|
+
|
|
65
|
+
if (!context || !name || !value) {
|
|
66
|
+
return currentMap;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!currentMap[context]) {
|
|
70
|
+
currentMap[context] = {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
currentMap[context][name] = value;
|
|
74
|
+
return currentMap;
|
|
75
|
+
}, {});
|
|
76
|
+
|
|
77
|
+
const decodeOrderOtherInformations = order =>
|
|
78
|
+
parseJsonObject(
|
|
79
|
+
order?.otherInformations ??
|
|
80
|
+
order?.other_information ??
|
|
81
|
+
order?.otherInformation ??
|
|
82
|
+
order?.otherInformationsJson ??
|
|
83
|
+
order?.other_information_json,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const getContextFromOtherInformations = (order, context) => {
|
|
87
|
+
const otherInformations = decodeOrderOtherInformations(order);
|
|
88
|
+
const matchedKey = Object.keys(otherInformations).find(
|
|
89
|
+
key => normalizeKey(key) === normalizeKey(context),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (!matchedKey) {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const matchedValue = otherInformations?.[matchedKey];
|
|
97
|
+
return isObject(matchedValue) ? matchedValue : parseJsonObject(matchedValue);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const findNestedFieldValue = (source, fieldName) => {
|
|
101
|
+
if (Array.isArray(source)) {
|
|
102
|
+
for (const entry of source) {
|
|
103
|
+
const nestedValue = findNestedFieldValue(entry, fieldName);
|
|
104
|
+
if (nestedValue) {
|
|
105
|
+
return nestedValue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!isObject(source)) {
|
|
113
|
+
return '';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const normalizedFieldName = normalizeKey(fieldName);
|
|
117
|
+
const matchedKey = Object.keys(source).find(
|
|
118
|
+
key => normalizeKey(key) === normalizedFieldName,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (matchedKey) {
|
|
122
|
+
const directValue = normalizeText(source?.[matchedKey]);
|
|
123
|
+
if (directValue) {
|
|
124
|
+
return directValue;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
for (const value of Object.values(source)) {
|
|
129
|
+
const nestedValue = findNestedFieldValue(value, fieldName);
|
|
130
|
+
if (nestedValue) {
|
|
131
|
+
return nestedValue;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return '';
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const getMarketplaceField = (order, contexts, fieldName) => {
|
|
139
|
+
const extraDataMap = getExtraDataMap(order);
|
|
140
|
+
|
|
141
|
+
for (const context of contexts) {
|
|
142
|
+
const value = normalizeText(extraDataMap?.[normalizeKey(context)]?.[fieldName]);
|
|
143
|
+
if (value) {
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (const context of contexts) {
|
|
149
|
+
const value = findNestedFieldValue(
|
|
150
|
+
getContextFromOtherInformations(order, context),
|
|
151
|
+
fieldName,
|
|
152
|
+
);
|
|
153
|
+
if (value) {
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return '';
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const resolveMarketplaceLabel = order => {
|
|
162
|
+
const normalizedApp = normalizeText(order?.app).toLowerCase();
|
|
163
|
+
|
|
164
|
+
if (normalizedApp.includes('99')) {
|
|
165
|
+
return '99';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (normalizedApp.includes('ifood')) {
|
|
169
|
+
return 'IFOOD';
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return normalizeText(order?.app).toUpperCase();
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const resolveMarketplaceOrderCodeFromOrder = order => {
|
|
176
|
+
const normalizedApp = normalizeText(order?.app).toLowerCase();
|
|
177
|
+
|
|
178
|
+
if (normalizedApp.includes('99')) {
|
|
179
|
+
return getMarketplaceField(order, ['Food99', '99Food', '99food'], 'code');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (normalizedApp.includes('ifood')) {
|
|
183
|
+
return getMarketplaceField(order, ['iFood', 'IFood', 'ifood'], 'code');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return '';
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const resolveMarketplaceOrderCodeFromSummary = remoteOrderSummary => {
|
|
190
|
+
if (!remoteOrderSummary || typeof remoteOrderSummary !== 'object') {
|
|
191
|
+
return '';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return normalizeText(
|
|
195
|
+
remoteOrderSummary?.identifiers?.code ||
|
|
196
|
+
remoteOrderSummary?.identifiers?.externalId ||
|
|
197
|
+
remoteOrderSummary?.code ||
|
|
198
|
+
remoteOrderSummary?.externalId ||
|
|
199
|
+
remoteOrderSummary?.external_code,
|
|
200
|
+
);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const resolvePosExternalCode = order =>
|
|
204
|
+
normalizeText(
|
|
205
|
+
normalizeText(order?.app).toUpperCase() === 'POS'
|
|
206
|
+
? order?.externalCode || order?.external_code || order?.externalId
|
|
207
|
+
: '',
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const resolvePosExternalLabel = () =>
|
|
211
|
+
global.t?.t('orders', 'title', 'table') || 'Table';
|
|
212
|
+
|
|
213
|
+
export const resolveMarketplaceAppLabel = order => resolveMarketplaceLabel(order);
|
|
214
|
+
|
|
215
|
+
export const resolveMarketplaceOrderCode = (
|
|
216
|
+
order,
|
|
217
|
+
remoteOrderSummary = null,
|
|
218
|
+
) =>
|
|
219
|
+
resolveMarketplaceOrderCodeFromSummary(remoteOrderSummary) ||
|
|
220
|
+
resolveMarketplaceOrderCodeFromOrder(order);
|
|
221
|
+
|
|
222
|
+
export const resolveOrderIdentityRemoteSummary = (
|
|
223
|
+
order,
|
|
224
|
+
remoteOrderSummary = null,
|
|
225
|
+
) => remoteOrderSummary || null;
|
|
226
|
+
|
|
227
|
+
export const resolveOrderIdentity = (order, remoteOrderSummary = null) => {
|
|
228
|
+
const effectiveRemoteOrderSummary = resolveOrderIdentityRemoteSummary(
|
|
229
|
+
order,
|
|
230
|
+
remoteOrderSummary,
|
|
231
|
+
);
|
|
232
|
+
const internalId = normalizeText(order?.id);
|
|
233
|
+
const marketplaceLabel = resolveMarketplaceAppLabel(order);
|
|
234
|
+
const marketplaceOrderCode = resolveMarketplaceOrderCode(
|
|
235
|
+
order,
|
|
236
|
+
effectiveRemoteOrderSummary,
|
|
237
|
+
);
|
|
238
|
+
const posExternalCode = resolvePosExternalCode(order);
|
|
239
|
+
const hasMarketplaceReference = !!marketplaceLabel && !!marketplaceOrderCode;
|
|
240
|
+
|
|
241
|
+
if (posExternalCode) {
|
|
242
|
+
return {
|
|
243
|
+
internalId,
|
|
244
|
+
externalId: posExternalCode,
|
|
245
|
+
externalLabel: '',
|
|
246
|
+
hasMarketplaceReference: false,
|
|
247
|
+
primaryText: [resolvePosExternalLabel(), formatOrderCode(posExternalCode)]
|
|
248
|
+
.filter(Boolean)
|
|
249
|
+
.join(' '),
|
|
250
|
+
secondaryText:
|
|
251
|
+
normalizeText(posExternalCode) === internalId
|
|
252
|
+
? ''
|
|
253
|
+
: formatOrderCode(internalId),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (hasMarketplaceReference) {
|
|
258
|
+
return {
|
|
259
|
+
internalId,
|
|
260
|
+
externalId: marketplaceOrderCode,
|
|
261
|
+
externalLabel: marketplaceLabel,
|
|
262
|
+
hasMarketplaceReference: true,
|
|
263
|
+
primaryText: formatOrderCode(marketplaceOrderCode),
|
|
264
|
+
secondaryText: formatOrderCode(internalId),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
internalId,
|
|
270
|
+
externalId: '',
|
|
271
|
+
externalLabel: '',
|
|
272
|
+
hasMarketplaceReference: false,
|
|
273
|
+
primaryText:
|
|
274
|
+
formatOrderCode(internalId) || global.t?.t('orders', 'title', 'order'),
|
|
275
|
+
secondaryText: '',
|
|
276
|
+
};
|
|
277
|
+
};
|