@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.
Files changed (188) 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 +32 -28
  11. package/src/api/fetch.js +1 -1
  12. package/src/api/index.js +328 -58
  13. package/src/react/components/AddImportModal.js +95 -111
  14. package/src/react/components/AnimatedModal.js +171 -0
  15. package/src/react/components/AnimatedModal.styles.js +21 -0
  16. package/src/react/components/AppTypeSwitcher.js +164 -0
  17. package/src/react/components/AppTypeSwitcher.styles.js +109 -0
  18. package/src/react/components/BackgroundRuntimeBridge.js +5 -4
  19. package/src/react/components/BottomNavigationBar.config.js +211 -231
  20. package/src/react/components/BottomNavigationBar.js +86 -31
  21. package/src/react/components/BottomNavigationBar.styles.js +118 -110
  22. package/src/react/components/CategoryForm.js +52 -35
  23. package/src/react/components/DefaultProvider.native.js +194 -156
  24. package/src/react/components/DefaultProvider.web.js +188 -112
  25. package/src/react/components/DeliveryPushBridge.native.js +2 -2
  26. package/src/react/components/DeviceAlertSoundService.js +3 -3
  27. package/src/react/components/KioskModeBridge.js +2 -2
  28. package/src/react/components/LauncherModeBridge.js +2 -2
  29. package/src/react/components/ManagerPushBridge.native.js +2 -2
  30. package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
  31. package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
  32. package/src/react/components/RemoteCheckoutService.js +28 -20
  33. package/src/react/components/RuntimeBottomNavigationBar.js +146 -119
  34. package/src/react/components/RuntimeInfoFooter.js +137 -45
  35. package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
  36. package/src/react/components/StateStore.js +258 -0
  37. package/src/react/components/UnifiedPaymentBar.js +7 -4
  38. package/src/react/components/UserAvatar.js +160 -0
  39. package/src/react/components/WebsocketListener.native.js +11 -11
  40. package/src/react/components/integrations/IntegrationHero/index.js +48 -0
  41. package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
  42. package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
  43. package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
  44. package/src/react/config/deviceConfigBootstrap.js +71 -30
  45. package/src/react/css/orders.js +72 -0
  46. package/src/react/pages/Connections.js +229 -0
  47. package/src/react/pages/Connections.styles.js +222 -0
  48. package/src/react/pages/DeviceDetailPage.js +2814 -0
  49. package/src/react/pages/DeviceDetailPage.styles.js +308 -0
  50. package/src/react/pages/Devices/currentDevice.js +194 -0
  51. package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
  52. package/src/react/pages/Devices/deviceTypes/all.js +23 -0
  53. package/src/react/pages/Devices/deviceTypes/device.js +25 -0
  54. package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
  55. package/src/react/pages/Devices/deviceTypes/display.js +26 -0
  56. package/src/react/pages/Devices/deviceTypes/index.js +145 -0
  57. package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
  58. package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
  59. package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
  60. package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
  61. package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
  62. package/src/react/pages/Devices.js +183 -0
  63. package/src/react/pages/Devices.styles.js +353 -0
  64. package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
  65. package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
  66. package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
  67. package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
  68. package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
  69. package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
  70. package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
  71. package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
  72. package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
  73. package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
  74. package/src/react/pages/Food99IntegrationPage.js +1 -0
  75. package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
  76. package/src/react/pages/GenericLogPage.js +42 -167
  77. package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
  78. package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
  79. package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
  80. package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
  81. package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
  82. package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
  83. package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
  84. package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
  85. package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
  86. package/src/react/pages/IFoodIntegrationPage.js +1 -0
  87. package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
  88. package/src/react/pages/Imports.js +214 -166
  89. package/src/react/pages/IntegrationConfigPage.js +744 -0
  90. package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
  91. package/src/react/pages/Integrations.js +299 -0
  92. package/src/react/pages/Integrations.styles.js +130 -0
  93. package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
  94. package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
  95. package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
  96. package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
  97. package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
  98. package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
  99. package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
  100. package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
  101. package/src/react/pages/PrinterDeviceFormPage.js +521 -0
  102. package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
  103. package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +484 -454
  104. package/src/react/pages/SettingsPage/index.js +1266 -1167
  105. package/src/react/pages/WhatsAppConnectionPage.js +459 -0
  106. package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
  107. package/src/react/pages/integrationsCatalog.js +399 -0
  108. package/src/react/print/providers/local.js +1 -1
  109. package/src/react/router/publicRoutes.js +25 -0
  110. package/src/react/services/Cielo/Checkout.js +39 -0
  111. package/src/react/services/Cielo/Cielo.js +193 -0
  112. package/src/react/services/Cielo/Print.js +7 -0
  113. package/src/react/services/InfinitePay/Checkout.js +33 -0
  114. package/src/react/services/InfinitePay/InfinitePay.js +24 -0
  115. package/src/react/{utils → services}/paymentGatewayExecution.js +91 -91
  116. package/src/react/styles/global.js +115 -0
  117. package/src/react/utils/categoryContexts.js +46 -0
  118. package/src/react/utils/entityDisplay.js +222 -217
  119. package/src/react/utils/fileUrl.js +201 -16
  120. package/src/react/utils/integrationPage.js +16 -0
  121. package/src/react/utils/menuNavigation.js +31 -0
  122. package/src/react/utils/orderIdentity.js +277 -0
  123. package/src/react/utils/remotePayment.js +115 -61
  124. package/src/react/utils/runtimeFooter.js +40 -22
  125. package/src/react/utils/runtimeLanguage.js +50 -9
  126. package/src/react/utils/runtimeMenu.js +190 -98
  127. package/src/react/utils/runtimeZoom.js +43 -0
  128. package/src/react/utils/shopConfig.js +72 -34
  129. package/src/react/utils/shopFranchises.js +182 -23
  130. package/src/react/utils/socketRuntimePipeline.js +14 -14
  131. package/src/react/utils/storeColumns.js +23 -4
  132. package/src/react/utils/userAvatar.js +104 -0
  133. package/src/store/categories/index.js +48 -20
  134. package/src/store/configs/index.js +2 -2
  135. package/src/store/device_config/index.js +62 -21
  136. package/src/store/entity_log/index.js +22 -1
  137. package/src/store/imports/customActions.js +51 -0
  138. package/src/store/imports/index.js +89 -88
  139. package/src/store/status/index.js +11 -11
  140. package/src/store/themes/index.js +22 -0
  141. package/src/store/timezones/index.js +3 -1
  142. package/src/tests/browser/manager/connections.spec.js +143 -0
  143. package/src/tests/browser/manager/devices-current.spec.js +343 -0
  144. package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
  145. package/src/tests/react/api/deviceHeaders.test.js +114 -0
  146. package/src/tests/react/api/loadSmokeIndex.test.js +75 -0
  147. package/src/tests/react/components/AddImportModal.test.js +166 -0
  148. package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
  149. package/src/tests/react/components/UserAvatar.test.js +52 -0
  150. package/src/tests/react/config/deviceConfigBootstrap.test.js +47 -0
  151. package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
  152. package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
  153. package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
  154. package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
  155. package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
  156. package/src/tests/react/print/localPrintProvider.test.js +1 -1
  157. package/src/tests/react/services/Cielo.test.js +190 -0
  158. package/src/tests/react/store/categoriesOrdering.test.js +26 -0
  159. package/src/tests/react/utils/appDomain.test.js +62 -0
  160. package/src/tests/react/utils/entityDisplay.test.js +2 -2
  161. package/src/tests/react/utils/fileUrl.test.js +62 -0
  162. package/src/tests/react/utils/formatter.test.mjs +33 -0
  163. package/src/tests/react/utils/importStatus.test.js +2 -2
  164. package/src/tests/react/utils/orderIdentity.test.js +139 -0
  165. package/src/tests/react/utils/remotePayment.test.js +62 -0
  166. package/src/tests/react/utils/runtimeFooter.test.js +32 -9
  167. package/src/tests/react/utils/runtimeLanguage.test.js +80 -10
  168. package/src/tests/react/utils/runtimeMenu.test.js +195 -111
  169. package/src/tests/react/utils/runtimeZoom.test.js +38 -0
  170. package/src/tests/react/utils/shopConfig.test.js +75 -0
  171. package/src/tests/react/utils/shopFranchises.test.js +122 -12
  172. package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
  173. package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
  174. package/src/tests/react/utils/translate.test.mjs +252 -396
  175. package/src/tests/react/utils/userAvatar.test.js +63 -0
  176. package/src/utils/appDomain.js +15 -4
  177. package/src/utils/formatter.js +122 -16
  178. package/src/utils/integrationConfigs.js +1 -0
  179. package/src/utils/translate.js +277 -398
  180. package/src/utils/translateDiscovery.js +96 -0
  181. package/src/utils/translateNormalize.js +33 -0
  182. package/src/utils/translatePending.js +92 -0
  183. package/src/utils/translateStorage.js +142 -0
  184. package/.github/agents/developer.agent.md +0 -30
  185. package/.github/agents/devops.agent.md +0 -30
  186. package/.github/agents/qa.agent.md +0 -30
  187. package/.github/agents/security.agent.md +0 -30
  188. package/.github/workflows/npmjs.yml +0 -35
@@ -1,11 +1,12 @@
1
- import { env as APP_ENV } from '@env';
2
- import { buildAssetUrl } from '@controleonline/../../src/styles/branding';
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
- // Centraliza a resolucao de imagem/arquivo do backend em uma unica regra.
81
- export const resolveFileImageUrl = (file, {company = null, appDomain = ''} = {}) => {
182
+ export const resolveDefaultFileSource = (
183
+ file,
184
+ {company = null, appDomain = '', headers = {}} = {},
185
+ ) => {
82
186
  const normalizedFile = unwrapFile(file);
83
- const directUrl = resolveDirectFileUrl(normalizedFile);
84
- if (directUrl) {
85
- return directUrl;
187
+ const host = resolveDownloadHost({company, appDomain});
188
+
189
+ if (!normalizedFile) {
190
+ return null;
86
191
  }
87
192
 
88
- const fileId = extractFileId(normalizedFile);
89
- if (!fileId) {
90
- return '';
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
- const fallbackDomain = normalizeText(appDomain) || resolveAppDomain(APP_ENV?.DOMAIN);
94
- const host = resolveCompanyDomain(company, fallbackDomain);
95
- const query = host ? `?app-domain=${encodeURIComponent(host)}` : '';
96
- const relativeUrl = `/files/${fileId}/download${query}`;
97
- const apiEntryPoint = normalizeText(APP_ENV?.API_ENTRYPOINT).replace(/\/$/, '');
204
+ if (typeof normalizedFile === 'string') {
205
+ const normalizedValue = normalizeText(normalizedFile);
206
+ if (!normalizedValue) {
207
+ return null;
208
+ }
98
209
 
99
- return apiEntryPoint ? `${apiEntryPoint}${relativeUrl}` : relativeUrl;
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
+ };