@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,61 +1,115 @@
1
- import {getPaymentOptionId, getPaymentOptionLabel} from './paymentOptions';
2
-
3
- export const REMOTE_PAYMENT_MESSAGE_STORE = 'invoice';
4
- export const REMOTE_PAYMENT_REQUEST_ACTION = 'pay';
5
- export const REMOTE_PAYMENT_RESULT_ACTION = 'pay-result';
6
-
7
- const normalizeText = value => String(value || '').trim();
8
-
9
- const normalizeOrderId = value => normalizeText(value).replace(/\D/g, '');
10
-
11
- export const normalizeRemotePaymentRequestKey = value => normalizeText(value);
12
-
13
- export const buildRemotePaymentRequestKey = ({
14
- orderId,
15
- payment,
16
- targetDeviceId,
17
- }) =>
18
- [
19
- normalizeOrderId(orderId) || 'order',
20
- normalizeText(targetDeviceId) || 'device',
21
- getPaymentOptionId(payment) || 'payment',
22
- Date.now().toString(),
23
- ].join(':');
24
-
25
- export const isRemotePaymentRequestMessage = message =>
26
- normalizeText(message?.action).toLowerCase() ===
27
- REMOTE_PAYMENT_REQUEST_ACTION;
28
-
29
- export const isRemotePaymentResultMessage = message =>
30
- normalizeText(message?.action).toLowerCase() ===
31
- REMOTE_PAYMENT_RESULT_ACTION;
32
-
33
- export const buildRemotePaymentResultMessage = ({
34
- destinationDeviceId,
35
- error = '',
36
- invoice = null,
37
- orderId,
38
- paidAmount = 0,
39
- payment = null,
40
- requestKey,
41
- status = 'error',
42
- targetDeviceId,
43
- targetDeviceLabel = '',
44
- targetGateway = '',
45
- total = 0,
46
- }) => ({
47
- destination: normalizeText(destinationDeviceId),
48
- store: REMOTE_PAYMENT_MESSAGE_STORE,
49
- action: REMOTE_PAYMENT_RESULT_ACTION,
50
- requestKey: normalizeRemotePaymentRequestKey(requestKey),
51
- status: normalizeText(status).toLowerCase() === 'success' ? 'success' : 'error',
52
- order: normalizeOrderId(orderId),
53
- total: Number(total || 0),
54
- paidAmount: Number(paidAmount || 0),
55
- paymentLabel: getPaymentOptionLabel(payment),
56
- targetDeviceId: normalizeText(targetDeviceId),
57
- targetDeviceLabel: normalizeText(targetDeviceLabel),
58
- targetGateway: normalizeText(targetGateway),
59
- ...(invoice ? {invoice} : {}),
60
- ...(error ? {error: normalizeText(error)} : {}),
61
- });
1
+ import {getPaymentOptionId, getPaymentOptionLabel} from './paymentOptions';
2
+
3
+ export const REMOTE_PAYMENT_MESSAGE_STORE = 'invoice';
4
+ export const REMOTE_PAYMENT_REQUEST_ACTION = 'pay';
5
+ export const REMOTE_PAYMENT_RESULT_ACTION = 'pay-result';
6
+ export const REMOTE_PAYMENT_STATUS_SUCCESS = 'success';
7
+ export const REMOTE_PAYMENT_STATUS_ERROR = 'error';
8
+ export const REMOTE_PAYMENT_STATUS_CANCELED = 'canceled';
9
+
10
+ const normalizeText = value => String(value || '').trim();
11
+
12
+ const normalizeSearchText = value =>
13
+ normalizeText(value)
14
+ .normalize('NFD')
15
+ .replace(/[\u0300-\u036f]/g, '')
16
+ .toLowerCase();
17
+
18
+ const EXPLICIT_CANCELLATION_STATUSES = new Set([
19
+ 'cancel',
20
+ 'canceled',
21
+ 'cancelled',
22
+ ]);
23
+
24
+ const isCancellationErrorText = value => {
25
+ const text = normalizeSearchText(value);
26
+
27
+ if (!text || /(?:nao|not) (?:foi )?(?:possivel )?cancel/.test(text)) {
28
+ return false;
29
+ }
30
+
31
+ return (
32
+ /\bcancelad[ao]s?\b/.test(text) ||
33
+ /\bcancell?ed\b/.test(text) ||
34
+ /\bcancelamento\b.*\b(?:usuario|cliente)\b/.test(text)
35
+ );
36
+ };
37
+
38
+ /*
39
+ * @agents A customer cancellation is a neutral terminal outcome. Older remote
40
+ * devices reported it as status=error, so keep the text fallback until every
41
+ * deployed device sends the canonical canceled status.
42
+ */
43
+ export const normalizeRemotePaymentResultStatus = ({status, error} = {}) => {
44
+ const normalizedStatus = normalizeText(status).toLowerCase();
45
+
46
+ if (normalizedStatus === REMOTE_PAYMENT_STATUS_SUCCESS) {
47
+ return REMOTE_PAYMENT_STATUS_SUCCESS;
48
+ }
49
+
50
+ if (
51
+ EXPLICIT_CANCELLATION_STATUSES.has(normalizedStatus) ||
52
+ isCancellationErrorText(error)
53
+ ) {
54
+ return REMOTE_PAYMENT_STATUS_CANCELED;
55
+ }
56
+
57
+ return REMOTE_PAYMENT_STATUS_ERROR;
58
+ };
59
+
60
+ export const isRemotePaymentCancellation = result =>
61
+ normalizeRemotePaymentResultStatus(result) === REMOTE_PAYMENT_STATUS_CANCELED;
62
+
63
+ const normalizeOrderId = value => normalizeText(value).replace(/\D/g, '');
64
+
65
+ export const normalizeRemotePaymentRequestKey = value => normalizeText(value);
66
+
67
+ export const buildRemotePaymentRequestKey = ({
68
+ orderId,
69
+ payment,
70
+ targetDeviceId,
71
+ }) =>
72
+ [
73
+ normalizeOrderId(orderId) || 'order',
74
+ normalizeText(targetDeviceId) || 'device',
75
+ getPaymentOptionId(payment) || 'payment',
76
+ Date.now().toString(),
77
+ ].join(':');
78
+
79
+ export const isRemotePaymentRequestMessage = message =>
80
+ normalizeText(message?.action).toLowerCase() ===
81
+ REMOTE_PAYMENT_REQUEST_ACTION;
82
+
83
+ export const isRemotePaymentResultMessage = message =>
84
+ normalizeText(message?.action).toLowerCase() ===
85
+ REMOTE_PAYMENT_RESULT_ACTION;
86
+
87
+ export const buildRemotePaymentResultMessage = ({
88
+ destinationDeviceId,
89
+ error = '',
90
+ invoice = null,
91
+ orderId,
92
+ paidAmount = 0,
93
+ payment = null,
94
+ requestKey,
95
+ status = 'error',
96
+ targetDeviceId,
97
+ targetDeviceLabel = '',
98
+ targetGateway = '',
99
+ total = 0,
100
+ }) => ({
101
+ destination: normalizeText(destinationDeviceId),
102
+ store: REMOTE_PAYMENT_MESSAGE_STORE,
103
+ action: REMOTE_PAYMENT_RESULT_ACTION,
104
+ requestKey: normalizeRemotePaymentRequestKey(requestKey),
105
+ status: normalizeRemotePaymentResultStatus({status, error}),
106
+ order: normalizeOrderId(orderId),
107
+ total: Number(total || 0),
108
+ paidAmount: Number(paidAmount || 0),
109
+ paymentLabel: getPaymentOptionLabel(payment),
110
+ targetDeviceId: normalizeText(targetDeviceId),
111
+ targetDeviceLabel: normalizeText(targetDeviceLabel),
112
+ targetGateway: normalizeText(targetGateway),
113
+ ...(invoice ? {invoice} : {}),
114
+ ...(error ? {error: normalizeText(error)} : {}),
115
+ });
@@ -90,27 +90,43 @@ const parseObjectValue = value => {
90
90
  const parseDeviceMetadata = metadata => parseObjectValue(metadata);
91
91
  const parseDeviceConfigs = configs => parseObjectValue(configs);
92
92
 
93
- const normalizeRuntimeFooterText = value => {
94
- if (value === null || value === undefined) {
95
- return '';
96
- }
93
+ const normalizeRuntimeFooterText = value => {
94
+ if (value === null || value === undefined) {
95
+ return '';
96
+ }
97
97
 
98
98
  const parsedValue =
99
99
  typeof value === 'string' ? parseJsonStringValue(value) : value;
100
100
 
101
- if (parsedValue && typeof parsedValue === 'object') {
102
- return '';
103
- }
104
-
105
- const normalized = safeTrim(parsedValue);
106
-
107
- return normalized.replace(/\s+/g, ' ');
108
- };
109
-
110
- const getRuntimeFooterText = company =>
111
- normalizeRuntimeFooterText(
112
- company?.configs?.[DEVICE_RUNTIME_FOOTER_TEXT_CONFIG_KEY],
113
- );
101
+ if (parsedValue && typeof parsedValue === 'object') {
102
+ return '';
103
+ }
104
+
105
+ return safeTrim(String(parsedValue).replace(/\r\n?/g, '\n'))
106
+ .split('\n')
107
+ .map(line => safeTrim(line).replace(/\s+/g, ' '))
108
+ .filter(Boolean)
109
+ .join('\n');
110
+ };
111
+
112
+ const getRuntimeFooterText = company =>
113
+ normalizeRuntimeFooterText(
114
+ company?.configs?.[DEVICE_RUNTIME_FOOTER_TEXT_CONFIG_KEY],
115
+ );
116
+
117
+ const getRuntimeFooterTextLines = value => {
118
+ const normalizedText =
119
+ typeof value === 'string'
120
+ ? normalizeRuntimeFooterText(value)
121
+ : getRuntimeFooterText(value);
122
+
123
+ return normalizedText ? normalizedText.split('\n').filter(Boolean) : [];
124
+ };
125
+
126
+ const getRuntimeFooterRotationEntries = ({companyFooterText, primaryText}) =>
127
+ [...getRuntimeFooterTextLines(companyFooterText), safeTrim(primaryText)].filter(
128
+ Boolean,
129
+ );
114
130
 
115
131
  const isWebRuntimeDevice = device => {
116
132
  const metadata = parseDeviceMetadata(device?.metadata);
@@ -465,11 +481,13 @@ module.exports = {
465
481
  getRuntimeFooterDebugInfo,
466
482
  getRuntimeFooterDeviceName,
467
483
  getRuntimeFooterNativeIdentifierCandidates,
468
- getRuntimeFooterPrimaryText,
469
- getRuntimeFooterStoredVersion,
470
- getRuntimeFooterVersionCandidates,
471
- getRuntimeFooterWebIdentifierCandidates,
472
- getRuntimeFooterText,
484
+ getRuntimeFooterPrimaryText,
485
+ getRuntimeFooterRotationEntries,
486
+ getRuntimeFooterStoredVersion,
487
+ getRuntimeFooterTextLines,
488
+ getRuntimeFooterVersionCandidates,
489
+ getRuntimeFooterWebIdentifierCandidates,
490
+ getRuntimeFooterText,
473
491
  getRuntimeFooterWebHost,
474
492
  normalizeRuntimeFooterText,
475
493
  };
@@ -27,7 +27,7 @@ function resolveCompanyLanguageCode(company) {
27
27
  return ''
28
28
  }
29
29
 
30
- function resolveConfiguredLanguage({
30
+ function resolveConfiguredLanguage({
31
31
  currentCompany,
32
32
  defaultCompany,
33
33
  currentConfig,
@@ -40,11 +40,52 @@ function resolveConfiguredLanguage({
40
40
  normalizeLanguageCode(currentConfig?.language) ||
41
41
  normalizeLanguageCode(sessionData?.language) ||
42
42
  fallback
43
- )
44
- }
45
-
46
- module.exports = {
47
- normalizeLanguageCode,
48
- resolveCompanyLanguageCode,
49
- resolveConfiguredLanguage,
50
- }
43
+ )
44
+ }
45
+
46
+ function buildTranslationBootstrapKey({
47
+ language,
48
+ currentCompanyId,
49
+ defaultCompanyId,
50
+ } = {}) {
51
+ const normalizedLanguage = normalizeLanguageCode(language)
52
+ const normalizedCurrentCompanyId = String(currentCompanyId || '').trim()
53
+ const normalizedDefaultCompanyId = String(defaultCompanyId || '').trim()
54
+
55
+ if (!normalizedLanguage || !normalizedCurrentCompanyId) {
56
+ return ''
57
+ }
58
+
59
+ return [
60
+ normalizedLanguage,
61
+ normalizedCurrentCompanyId,
62
+ normalizedDefaultCompanyId,
63
+ ].join('::')
64
+ }
65
+
66
+ function isTranslationBootstrapReady({
67
+ activeKey,
68
+ expectedKey,
69
+ required,
70
+ ready,
71
+ translator,
72
+ } = {}) {
73
+ if (!required) {
74
+ return true
75
+ }
76
+
77
+ return Boolean(
78
+ expectedKey &&
79
+ activeKey === expectedKey &&
80
+ ready === true &&
81
+ typeof translator?.t === 'function',
82
+ )
83
+ }
84
+
85
+ module.exports = {
86
+ buildTranslationBootstrapKey,
87
+ isTranslationBootstrapReady,
88
+ normalizeLanguageCode,
89
+ resolveCompanyLanguageCode,
90
+ resolveConfiguredLanguage,
91
+ }
@@ -3,30 +3,30 @@ export const normalizeAppType = value => {
3
3
  return normalized || 'MANAGER';
4
4
  };
5
5
 
6
- const RUNTIME_MENU_ICON_ALIASES = {
7
- shopping_cart: 'shopping-cart',
8
- account_balance: 'dollar-sign',
9
- account_balance_wallet: 'credit-card',
10
- };
11
-
12
- export const normalizeRuntimeMenuType = (value, fallback = 'home') => {
13
- const normalized = String(value || '').trim().toLowerCase();
14
- return normalized || fallback;
15
- };
16
-
17
- const normalizeRuntimeMenuItem = (menu = {}) => ({
18
- ...menu,
19
- icon: normalizeRuntimeMenuIcon(menu?.icon),
20
- menuKey: String(menu?.menuKey || menu?.menu_key || '').trim(),
21
- menuType: normalizeRuntimeMenuType(menu?.menuType || menu?.menu_type),
22
- routeParams:
23
- menu?.routeParams && typeof menu.routeParams === 'object'
24
- ? menu.routeParams
25
- : {},
26
- sortOrder: Number(menu?.sortOrder ?? menu?.sort_order ?? 0),
27
- });
28
-
29
- const MANAGER_RUNTIME_MENU_FALLBACK = [
6
+ const RUNTIME_MENU_ICON_ALIASES = {
7
+ shopping_cart: 'shopping-cart',
8
+ account_balance: 'dollar-sign',
9
+ account_balance_wallet: 'credit-card',
10
+ };
11
+
12
+ export const normalizeRuntimeMenuType = (value, fallback = 'home') => {
13
+ const normalized = String(value || '').trim().toLowerCase();
14
+ return normalized || fallback;
15
+ };
16
+
17
+ const normalizeRuntimeMenuItem = (menu = {}) => ({
18
+ ...menu,
19
+ icon: normalizeRuntimeMenuIcon(menu?.icon),
20
+ menuKey: String(menu?.menuKey || menu?.menu_key || '').trim(),
21
+ menuType: normalizeRuntimeMenuType(menu?.menuType || menu?.menu_type),
22
+ routeParams:
23
+ menu?.routeParams && typeof menu.routeParams === 'object'
24
+ ? menu.routeParams
25
+ : {},
26
+ sortOrder: Number(menu?.sortOrder ?? menu?.sort_order ?? 0),
27
+ });
28
+
29
+ const MANAGER_RUNTIME_MENU_FALLBACK = [
30
30
  {
31
31
  id: 'manager-financeiro',
32
32
  label: 'Financeiro',
@@ -68,16 +68,25 @@ const MANAGER_RUNTIME_MENU_FALLBACK = [
68
68
  },
69
69
  ],
70
70
  },
71
- {
72
- id: 'manager-comercial',
73
- label: 'Comercial',
74
- icon: 'users',
75
- menus: [
76
- {
77
- id: 'clients',
78
- menuKey: 'clients',
79
- label: 'Cadastro de clientes',
80
- route: 'ClientsIndex',
71
+ {
72
+ id: 'manager-comercial',
73
+ label: 'Comercial',
74
+ icon: 'users',
75
+ menus: [
76
+ {
77
+ id: 'products',
78
+ menuKey: 'products',
79
+ label: 'Produtos',
80
+ route: 'ProductsPage',
81
+ icon: 'package',
82
+ color: '#16A34A',
83
+ sortOrder: 25,
84
+ },
85
+ {
86
+ id: 'clients',
87
+ menuKey: 'clients',
88
+ label: 'Cadastro de clientes',
89
+ route: 'ClientsIndex',
81
90
  icon: 'users',
82
91
  color: '#16A34A',
83
92
  sortOrder: 30,
@@ -125,48 +134,127 @@ const MANAGER_RUNTIME_MENU_FALLBACK = [
125
134
  color: '#64748B',
126
135
  sortOrder: 60,
127
136
  },
137
+ {
138
+ id: 'product_showcases',
139
+ menuKey: 'product_showcases',
140
+ label: 'Vitrines de preços',
141
+ route: 'ProductShowcasesPage',
142
+ icon: 'grid',
143
+ color: '#0F766E',
144
+ sortOrder: 65,
145
+ },
128
146
  ],
129
147
  },
130
148
  ];
131
149
 
132
- const cloneRuntimeMenuModules = modules =>
133
- (Array.isArray(modules) ? modules : []).map(module => ({
134
- ...module,
135
- menus: Array.isArray(module?.menus)
136
- ? module.menus.map(menu => normalizeRuntimeMenuItem(menu))
137
- : [],
138
- }));
150
+ const ADMIN_RUNTIME_MENU_FALLBACK = [
151
+ {
152
+ id: 'admin-configuracoes',
153
+ label: 'Configuracoes',
154
+ icon: 'settings',
155
+ menus: [
156
+ {
157
+ id: 'menu_access',
158
+ menuKey: 'menu_access',
159
+ label: 'Menus por perfil',
160
+ route: 'MenuAccessConfigPage',
161
+ icon: 'list',
162
+ color: '#64748B',
163
+ sortOrder: 10,
164
+ },
165
+ {
166
+ id: 'test_results',
167
+ menuKey: 'test_results',
168
+ label: 'Resultados de testes',
169
+ route: 'TestsPlaygroundPage',
170
+ icon: 'clipboard',
171
+ color: '#0EA5E9',
172
+ sortOrder: 20,
173
+ },
174
+ {
175
+ id: 'tenancies',
176
+ menuKey: 'tenancies',
177
+ label: 'Tenancies',
178
+ route: 'TenanciesPage',
179
+ icon: 'server',
180
+ color: '#0F766E',
181
+ sortOrder: 25,
182
+ },
183
+ {
184
+ id: 'people_domains',
185
+ menuKey: 'people_domains',
186
+ label: 'Domínios',
187
+ route: 'PeopleDomainsPage',
188
+ icon: 'globe',
189
+ color: '#0EA5E9',
190
+ sortOrder: 30,
191
+ },
192
+ {
193
+ id: 'flowcharts',
194
+ menuKey: 'flowcharts',
195
+ label: 'Fluxogramas',
196
+ route: 'FlowchartsPage',
197
+ icon: 'git-branch',
198
+ color: '#0F766E',
199
+ sortOrder: 40,
200
+ },
201
+ ],
202
+ },
203
+ ];
139
204
 
140
- export const normalizeRuntimeMenuIcon = value => {
141
- const normalized = String(value || '').trim();
142
- if (!normalized) return '';
205
+ const cloneRuntimeMenuModules = modules =>
206
+ (Array.isArray(modules) ? modules : []).map(module => ({
207
+ ...module,
208
+ menus: Array.isArray(module?.menus)
209
+ ? module.menus.map(menu => normalizeRuntimeMenuItem(menu))
210
+ : [],
211
+ }));
143
212
 
144
- return RUNTIME_MENU_ICON_ALIASES[normalized.toLowerCase()] || normalized;
145
- };
213
+ export const normalizeRuntimeMenuIcon = value => {
214
+ const normalized = String(value || '').trim();
215
+ if (!normalized) return '';
216
+
217
+ return RUNTIME_MENU_ICON_ALIASES[normalized.toLowerCase()] || normalized;
218
+ };
219
+
220
+ const resolveRuntimeModuleSortOrder = module => {
221
+ const explicitSortOrder = Number(module?.sortOrder ?? module?.sort_order);
222
+ if (Number.isFinite(explicitSortOrder)) {
223
+ return explicitSortOrder;
224
+ }
225
+
226
+ return 0;
227
+ };
146
228
 
147
- export const normalizeRuntimeMenuResponse = (
148
- result,
149
- {appType, allowFallback = true} = {},
150
- ) => {
229
+ export const normalizeRuntimeMenuResponse = (
230
+ result,
231
+ {appType, allowFallback = true} = {},
232
+ ) => {
151
233
  const modules =
152
234
  result?.response?.data?.modules ||
153
235
  result?.data?.modules ||
154
236
  result?.modules ||
155
237
  {};
156
238
 
157
- const normalizedModules = Object.values(modules)
158
- .map(module => ({
239
+ const normalizedModules = Object.values(modules)
240
+ .map(module => ({
159
241
  ...module,
160
242
  icon: normalizeRuntimeMenuIcon(module?.icon),
243
+ sortOrder: resolveRuntimeModuleSortOrder(module),
161
244
  menus: (Array.isArray(module?.menus) ? module.menus : [])
162
245
  .map(menu => normalizeRuntimeMenuItem(menu))
163
246
  .sort((left, right) => {
164
- const orderDiff = Number(left?.sortOrder || 0) - Number(right?.sortOrder || 0);
165
- if (orderDiff !== 0) return orderDiff;
166
- return String(left?.label || '').localeCompare(String(right?.label || ''));
167
- }),
168
- }))
169
- .filter(module => module.menus.length > 0);
247
+ const orderDiff = Number(left?.sortOrder || 0) - Number(right?.sortOrder || 0);
248
+ if (orderDiff !== 0) return orderDiff;
249
+ return String(left?.label || '').localeCompare(String(right?.label || ''));
250
+ }),
251
+ }))
252
+ .sort((left, right) => {
253
+ const orderDiff = Number(left?.sortOrder || 0) - Number(right?.sortOrder || 0);
254
+ if (orderDiff !== 0) return orderDiff;
255
+ return String(left?.label || '').localeCompare(String(right?.label || ''));
256
+ })
257
+ .filter(module => module.menus.length > 0);
170
258
 
171
259
  if (normalizedModules.length > 0) {
172
260
  return normalizedModules;
@@ -174,47 +262,51 @@ export const normalizeRuntimeMenuResponse = (
174
262
 
175
263
  const normalizedAppType = String(appType || '').trim().toUpperCase();
176
264
 
177
- if (allowFallback && normalizedAppType === 'MANAGER') {
178
- return cloneRuntimeMenuModules(MANAGER_RUNTIME_MENU_FALLBACK);
179
- }
265
+ if (allowFallback && normalizedAppType === 'MANAGER') {
266
+ return cloneRuntimeMenuModules(MANAGER_RUNTIME_MENU_FALLBACK);
267
+ }
180
268
 
181
- return [];
182
- };
183
-
184
- export const filterRuntimeMenuModulesByType = (menus, menuType) => {
185
- const normalizedMenuType =
186
- menuType === null || menuType === undefined || String(menuType).trim() === ''
187
- ? null
188
- : normalizeRuntimeMenuType(menuType, '');
189
-
190
- const modules = cloneRuntimeMenuModules(menus);
191
- if (!normalizedMenuType) {
192
- return modules;
193
- }
194
-
195
- return modules
196
- .map(module => ({
197
- ...module,
198
- menus: Array.isArray(module?.menus)
199
- ? module.menus.filter(
200
- menu => normalizeRuntimeMenuType(menu?.menuType, '') === normalizedMenuType,
201
- )
202
- : [],
203
- }))
204
- .filter(module => module.menus.length > 0);
205
- };
206
-
207
- export const flattenRuntimeMenuItemsByType = (menus, menuType) =>
208
- filterRuntimeMenuModulesByType(menus, menuType).flatMap(module =>
209
- Array.isArray(module?.menus) ? module.menus : [],
210
- );
211
-
212
- export const resolveRuntimeMenuLabel = (menu, translate) =>
213
- translate?.('menu', 'menu', menu?.menuKey) || menu?.label || menu?.menuKey || '';
214
-
215
- export const getRuntimeMenuRoutes = menus =>
216
- new Set(
217
- (Array.isArray(menus) ? menus : [])
269
+ if (allowFallback && normalizedAppType === 'ADMIN') {
270
+ return cloneRuntimeMenuModules(ADMIN_RUNTIME_MENU_FALLBACK);
271
+ }
272
+
273
+ return [];
274
+ };
275
+
276
+ export const filterRuntimeMenuModulesByType = (menus, menuType) => {
277
+ const normalizedMenuType =
278
+ menuType === null || menuType === undefined || String(menuType).trim() === ''
279
+ ? null
280
+ : normalizeRuntimeMenuType(menuType, '');
281
+
282
+ const modules = cloneRuntimeMenuModules(menus);
283
+ if (!normalizedMenuType) {
284
+ return modules;
285
+ }
286
+
287
+ return modules
288
+ .map(module => ({
289
+ ...module,
290
+ menus: Array.isArray(module?.menus)
291
+ ? module.menus.filter(
292
+ menu => normalizeRuntimeMenuType(menu?.menuType, '') === normalizedMenuType,
293
+ )
294
+ : [],
295
+ }))
296
+ .filter(module => module.menus.length > 0);
297
+ };
298
+
299
+ export const flattenRuntimeMenuItemsByType = (menus, menuType) =>
300
+ filterRuntimeMenuModulesByType(menus, menuType).flatMap(module =>
301
+ Array.isArray(module?.menus) ? module.menus : [],
302
+ );
303
+
304
+ export const resolveRuntimeMenuLabel = (menu, translate) =>
305
+ translate?.('menu', 'menu', menu?.menuKey) || menu?.label || menu?.menuKey || '';
306
+
307
+ export const getRuntimeMenuRoutes = menus =>
308
+ new Set(
309
+ (Array.isArray(menus) ? menus : [])
218
310
  .flatMap(module => (Array.isArray(module?.menus) ? module.menus : []))
219
311
  .map(menu => menu?.route)
220
312
  .filter(Boolean),