@controleonline/ui-common 1.2.70

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 (203) hide show
  1. package/.github/agents/developer.agent.md +30 -0
  2. package/.github/agents/devops.agent.md +30 -0
  3. package/.github/agents/qa.agent.md +30 -0
  4. package/.github/agents/security.agent.md +30 -0
  5. package/.github/workflows/npmjs.yml +35 -0
  6. package/.github/workflows/pull-request-checks.yml +19 -0
  7. package/.scrutinizer.yml +24 -0
  8. package/FUNDING.yml +1 -0
  9. package/package.json +28 -0
  10. package/src/api/fetch.js +74 -0
  11. package/src/api/index.js +155 -0
  12. package/src/api/localDB.js +131 -0
  13. package/src/api/queue.js +66 -0
  14. package/src/react/assets/tap.mp3 +0 -0
  15. package/src/react/components/AddImportModal.js +157 -0
  16. package/src/react/components/AddImportModal.styles.js +81 -0
  17. package/src/react/components/BackgroundRuntimeBridge.js +219 -0
  18. package/src/react/components/BottomNavigationBar.config.js +238 -0
  19. package/src/react/components/BottomNavigationBar.js +120 -0
  20. package/src/react/components/BottomNavigationBar.styles.js +110 -0
  21. package/src/react/components/CategoryForm.js +572 -0
  22. package/src/react/components/CategoryForm.styles.js +334 -0
  23. package/src/react/components/ConfirmModal.js +24 -0
  24. package/src/react/components/ConfirmModal.styles.js +43 -0
  25. package/src/react/components/ContextHelpButton.js +69 -0
  26. package/src/react/components/ContextHelpButton.styles.js +62 -0
  27. package/src/react/components/DefaultProvider.native.js +848 -0
  28. package/src/react/components/DefaultProvider.styles.js +21 -0
  29. package/src/react/components/DefaultProvider.web.js +909 -0
  30. package/src/react/components/DeliveryPushBridge.native.js +314 -0
  31. package/src/react/components/DeliveryPushBridge.web.js +5 -0
  32. package/src/react/components/DeviceAlertSoundService.js +499 -0
  33. package/src/react/components/EntityLogContent.js +909 -0
  34. package/src/react/components/EntityLogContent.styles.js +400 -0
  35. package/src/react/components/EventBus.js +12 -0
  36. package/src/react/components/KioskModeBridge.js +65 -0
  37. package/src/react/components/LauncherModeBridge.js +47 -0
  38. package/src/react/components/LinkedOrderProductsTab.js +388 -0
  39. package/src/react/components/LinkedOrderProductsTab.styles.js +180 -0
  40. package/src/react/components/ManagerPushBridge.native.js +345 -0
  41. package/src/react/components/MessageService.js +314 -0
  42. package/src/react/components/Paywall/Google.js +89 -0
  43. package/src/react/components/PrintService.js +778 -0
  44. package/src/react/components/ProductCatalogCacheService.js +45 -0
  45. package/src/react/components/RemoteCheckoutService.js +292 -0
  46. package/src/react/components/RuntimeBottomNavigationBar.js +151 -0
  47. package/src/react/components/RuntimeInfoFooter.js +214 -0
  48. package/src/react/components/RuntimeInfoFooter.styles.js +56 -0
  49. package/src/react/components/SystemErrorToast.js +29 -0
  50. package/src/react/components/SystemErrorToast.styles.js +38 -0
  51. package/src/react/components/TouchFeedbackProvider.js +65 -0
  52. package/src/react/components/UnifiedPaymentBar.js +155 -0
  53. package/src/react/components/UnifiedPaymentBar.styles.js +174 -0
  54. package/src/react/components/WebsocketListener.native.js +487 -0
  55. package/src/react/components/WebsocketListener.web.js +102 -0
  56. package/src/react/components/inputs/IdInput.js +49 -0
  57. package/src/react/components/inputs/IdInput.styles.js +26 -0
  58. package/src/react/components/inputs/InvoiceDueDateFilterInput.js +74 -0
  59. package/src/react/components/inputs/InvoiceDueDateFilterInput.styles.js +34 -0
  60. package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.js +115 -0
  61. package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.styles.js +39 -0
  62. package/src/react/components/lists/CategoriesList.js +56 -0
  63. package/src/react/components/lists/PaymentTypeList.js +55 -0
  64. package/src/react/components/lists/ReceiverList.js +56 -0
  65. package/src/react/components/lists/SelectList.styles.js +18 -0
  66. package/src/react/components/lists/StatusList.js +55 -0
  67. package/src/react/components/lists/WalletList.js +54 -0
  68. package/src/react/components/radio/Spotify.js +144 -0
  69. package/src/react/components/radio/Spotify.styles.js +32 -0
  70. package/src/react/components/radio/YouTube.js +82 -0
  71. package/src/react/components/radio/YouTube.styles.js +16 -0
  72. package/src/react/components/toastConfig.js +16 -0
  73. package/src/react/config/deviceConfigBootstrap.js +571 -0
  74. package/src/react/index.js +4 -0
  75. package/src/react/localStorage.js +30 -0
  76. package/src/react/pages/EntityLogPage.js +124 -0
  77. package/src/react/pages/EntityLogPage.styles.js +17 -0
  78. package/src/react/pages/GenericLogPage.js +760 -0
  79. package/src/react/pages/GenericLogPage.styles.js +401 -0
  80. package/src/react/pages/Imports.js +361 -0
  81. package/src/react/pages/Imports.styles.js +223 -0
  82. package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +462 -0
  83. package/src/react/pages/SettingsPage/index.js +1171 -0
  84. package/src/react/pages/SettingsPage/index.styles.js +122 -0
  85. package/src/react/print/jobs.js +147 -0
  86. package/src/react/print/providers/local.js +53 -0
  87. package/src/react/print/providers/remote.js +81 -0
  88. package/src/react/print/selection.js +296 -0
  89. package/src/react/print/usePrintButtonController.js +474 -0
  90. package/src/react/router/routes.js +42 -0
  91. package/src/react/services/NetworkPrinterService.native.js +391 -0
  92. package/src/react/services/NetworkPrinterService.web.js +15 -0
  93. package/src/react/stores/index.js +128 -0
  94. package/src/react/stores/storeErrorBridge.js +36 -0
  95. package/src/react/utils/backgroundRuntimeRegistration.js +69 -0
  96. package/src/react/utils/cashPayment.js +87 -0
  97. package/src/react/utils/commercialDocumentOrders.js +269 -0
  98. package/src/react/utils/dateRangeFilter.js +264 -0
  99. package/src/react/utils/deviceRuntime.js +193 -0
  100. package/src/react/utils/entityDisplay.js +231 -0
  101. package/src/react/utils/entityLog.js +649 -0
  102. package/src/react/utils/fileUrl.js +102 -0
  103. package/src/react/utils/frontendDebugLog.js +45 -0
  104. package/src/react/utils/googleMapsConfig.js +49 -0
  105. package/src/react/utils/importStatus.js +100 -0
  106. package/src/react/utils/invoiceDueDateMessages.js +14 -0
  107. package/src/react/utils/invoicePresentation.js +46 -0
  108. package/src/react/utils/logSettings.js +143 -0
  109. package/src/react/utils/maintenanceSettings.js +53 -0
  110. package/src/react/utils/managerOrderNotifications.js +523 -0
  111. package/src/react/utils/mapNavigation.js +76 -0
  112. package/src/react/utils/menuCatalogConfig.js +8 -0
  113. package/src/react/utils/menuCatalogDownload.js +157 -0
  114. package/src/react/utils/networkCameraDevices.js +175 -0
  115. package/src/react/utils/networkDeviceProfiles.js +135 -0
  116. package/src/react/utils/normalizedCatalogDownload.js +157 -0
  117. package/src/react/utils/notificationNavigation.js +94 -0
  118. package/src/react/utils/notificationSound.js +42 -0
  119. package/src/react/utils/paymentDevices.js +397 -0
  120. package/src/react/utils/paymentGatewayExecution.js +91 -0
  121. package/src/react/utils/paymentOptions.js +88 -0
  122. package/src/react/utils/peopleDisplay.js +39 -0
  123. package/src/react/utils/printerDevices.js +465 -0
  124. package/src/react/utils/remotePayment.js +61 -0
  125. package/src/react/utils/runtimeFooter.js +475 -0
  126. package/src/react/utils/runtimeLanguage.js +50 -0
  127. package/src/react/utils/runtimeMenu.js +224 -0
  128. package/src/react/utils/screenMetrics.js +30 -0
  129. package/src/react/utils/shopConfig.js +294 -0
  130. package/src/react/utils/shopFranchises.js +114 -0
  131. package/src/react/utils/socketRuntimePipeline.js +454 -0
  132. package/src/react/utils/spoolAckTracker.js +77 -0
  133. package/src/react/utils/storeColumns.js +427 -0
  134. package/src/react/utils/systemErrorChannel.js +109 -0
  135. package/src/react/utils/systemErrorMessage.js +67 -0
  136. package/src/react/utils/toastPresentation.js +53 -0
  137. package/src/react/utils/websocketSharedRuntime.js +826 -0
  138. package/src/store/acl/getters.js +4 -0
  139. package/src/store/acl/index.js +19 -0
  140. package/src/store/acl/mutation_types.js +4 -0
  141. package/src/store/acl/mutations.js +17 -0
  142. package/src/store/address/city.js +22 -0
  143. package/src/store/categories/category_file/index.js +25 -0
  144. package/src/store/categories/index.js +93 -0
  145. package/src/store/configs/customActions.js +131 -0
  146. package/src/store/configs/index.js +25 -0
  147. package/src/store/connections/customActions.js +26 -0
  148. package/src/store/connections/index.js +124 -0
  149. package/src/store/device/index.js +22 -0
  150. package/src/store/device_config/customActions.js +190 -0
  151. package/src/store/device_config/index.js +28 -0
  152. package/src/store/entity_log/customActions.js +63 -0
  153. package/src/store/entity_log/index.js +25 -0
  154. package/src/store/extra/data.js +85 -0
  155. package/src/store/extra/fields.js +88 -0
  156. package/src/store/file/actions.js +27 -0
  157. package/src/store/file/index.js +24 -0
  158. package/src/store/imports/index.js +88 -0
  159. package/src/store/print/customActions.js +251 -0
  160. package/src/store/print/index.js +28 -0
  161. package/src/store/printer/customActions.js +54 -0
  162. package/src/store/printer/index.js +26 -0
  163. package/src/store/runtime_debug/customActions.js +71 -0
  164. package/src/store/runtime_debug/index.js +30 -0
  165. package/src/store/status/index.js +65 -0
  166. package/src/store/timezones/index.js +43 -0
  167. package/src/store/websocket/customActions.js +24 -0
  168. package/src/store/websocket/index.js +28 -0
  169. package/src/tests/react/components/LauncherModeBridge.test.js +93 -0
  170. package/src/tests/react/config/deviceConfigBootstrap.test.js +337 -0
  171. package/src/tests/react/print/localPrintProvider.test.js +45 -0
  172. package/src/tests/react/utils/backgroundRuntimeRegistration.test.js +123 -0
  173. package/src/tests/react/utils/cashPayment.test.js +41 -0
  174. package/src/tests/react/utils/dateRangeFilter.test.mjs +29 -0
  175. package/src/tests/react/utils/entityDisplay.test.js +18 -0
  176. package/src/tests/react/utils/googleMapsConfig.test.js +32 -0
  177. package/src/tests/react/utils/importStatus.test.js +85 -0
  178. package/src/tests/react/utils/invoicePresentation.test.mjs +40 -0
  179. package/src/tests/react/utils/managerOrderNotifications.test.js +127 -0
  180. package/src/tests/react/utils/mapNavigation.test.js +58 -0
  181. package/src/tests/react/utils/notificationNavigation.test.js +39 -0
  182. package/src/tests/react/utils/notificationSound.test.js +27 -0
  183. package/src/tests/react/utils/paymentDevices.test.js +88 -0
  184. package/src/tests/react/utils/runtimeFooter.test.js +429 -0
  185. package/src/tests/react/utils/runtimeLanguage.test.js +80 -0
  186. package/src/tests/react/utils/runtimeMenu.test.js +174 -0
  187. package/src/tests/react/utils/shopFranchises.test.js +82 -0
  188. package/src/tests/react/utils/socketRuntimePipeline.test.js +124 -0
  189. package/src/tests/react/utils/spoolAckTracker.test.js +40 -0
  190. package/src/tests/react/utils/storeErrorBridge.test.js +66 -0
  191. package/src/tests/react/utils/systemErrorChannel.test.js +58 -0
  192. package/src/tests/react/utils/systemErrorMessage.test.js +59 -0
  193. package/src/tests/react/utils/toastPresentation.test.js +75 -0
  194. package/src/tests/react/utils/translate.test.mjs +396 -0
  195. package/src/tests/react/utils/websocketSharedRuntime.test.js +245 -0
  196. package/src/utils/apiEntryPoint.js +31 -0
  197. package/src/utils/appDomain.js +50 -0
  198. package/src/utils/config.js +14 -0
  199. package/src/utils/formatter.js +419 -0
  200. package/src/utils/integrationConfigs.js +79 -0
  201. package/src/utils/methods.js +23 -0
  202. package/src/utils/oauth.js +42 -0
  203. package/src/utils/translate.js +620 -0
@@ -0,0 +1,848 @@
1
+ import React, {
2
+ createContext,
3
+ useCallback,
4
+ useContext,
5
+ useEffect,
6
+ useMemo,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
10
+ import {View, AppState, Platform} from 'react-native';
11
+ import DeviceInfo from 'react-native-device-info';
12
+ import Translate from '@controleonline/ui-common/src/utils/translate';
13
+ import {WebsocketListener} from '@controleonline/ui-common/src/react/components/WebsocketListener';
14
+ import BackgroundRuntimeBridge from '@controleonline/ui-common/src/react/components/BackgroundRuntimeBridge';
15
+ import DeviceAlertSoundService from '@controleonline/ui-common/src/react/components/DeviceAlertSoundService';
16
+ import KioskModeBridge from '@controleonline/ui-common/src/react/components/KioskModeBridge';
17
+ import LauncherModeBridge from '@controleonline/ui-common/src/react/components/LauncherModeBridge';
18
+ import DeliveryPushBridge from '@controleonline/ui-common/src/react/components/DeliveryPushBridge';
19
+ import ManagerPushBridge from '@controleonline/ui-common/src/react/components/ManagerPushBridge';
20
+ import PrintService from '@controleonline/ui-common/src/react/components/PrintService';
21
+ import RemoteCheckoutService from '@controleonline/ui-common/src/react/components/RemoteCheckoutService';
22
+ import ProductCatalogCacheService from '@controleonline/ui-common/src/react/components/ProductCatalogCacheService';
23
+ import RuntimeInfoFooter from '@controleonline/ui-common/src/react/components/RuntimeInfoFooter';
24
+ import {isPublicRoute} from '@controleonline/ui-login/src/react/router/publicRoutes';
25
+ import {api} from '@controleonline/ui-common/src/api';
26
+ import {env as APP_ENV} from '@env';
27
+ const {resolveConfiguredLanguage} = require('../utils/runtimeLanguage');
28
+ import {
29
+ applyPaletteToRuntimeColors,
30
+ applyThemeCssVariables,
31
+ resolveThemePalette,
32
+ } from '@controleonline/../../src/styles/branding';
33
+ import {resolveAppDomain} from '@controleonline/ui-common/src/utils/appDomain';
34
+ import {colors as runtimeColors} from '@controleonline/../../src/styles/colors';
35
+ import {
36
+ buildProviderManagedDeviceConfigs,
37
+ parseConfigsObject,
38
+ } from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
39
+ import {
40
+ buildDeviceRegistrationPayload,
41
+ buildLocalRuntimeDevice,
42
+ hasDeviceRecordChanges,
43
+ resolveOperationalDeviceType,
44
+ } from '@controleonline/ui-common/src/react/utils/deviceRuntime';
45
+ import {
46
+ filterWalletPaymentTypesByAllowedIds,
47
+ resolveDevicePaymentTypeIds,
48
+ } from '@controleonline/ui-common/src/react/utils/paymentDevices';
49
+ import {normalizeRuntimeMenuResponse} from '@controleonline/ui-common/src/react/utils/runtimeMenu';
50
+ import packageJson from '@package';
51
+ import providerStyles from './DefaultProvider.styles';
52
+
53
+ import {useStore} from '@store';
54
+ import stores from '@stores';
55
+ const ThemeContext = createContext();
56
+
57
+ const parseThemeCss = cssText => {
58
+ const parsedColors = {};
59
+ const matches = String(cssText || '').match(/--([\w-]+)\s*:\s*([^;}{]+)\s*;/g) || [];
60
+
61
+ matches.forEach(match => {
62
+ const clean = match.trim().replace(/^--/, '').replace(/;$/, '');
63
+ const splitIndex = clean.indexOf(':');
64
+ if (splitIndex <= 0) return;
65
+
66
+ const key = clean.slice(0, splitIndex).trim();
67
+ const value = clean.slice(splitIndex + 1).trim();
68
+ if (!key || !value) return;
69
+ parsedColors[key] = value;
70
+ });
71
+
72
+ return parsedColors;
73
+ };
74
+
75
+ const normalizeEntityId = value =>
76
+ String(value?.id || value || '')
77
+ .replace(/\D/g, '')
78
+ .trim();
79
+
80
+ const resolveDeviceConfigPeopleIri = ({appType, currentCompany, user}) => {
81
+ const normalizedAppType = String(appType || '').trim().toUpperCase();
82
+ const currentPeopleId = normalizeEntityId(
83
+ user?.people ?? user?.peopleId ?? user?.person ?? user?.personId ?? '',
84
+ );
85
+ const currentCompanyId = normalizeEntityId(currentCompany?.id);
86
+
87
+ if (normalizedAppType === 'DELIVERY' && currentPeopleId) {
88
+ return `/people/${currentPeopleId}`;
89
+ }
90
+
91
+ if (currentCompanyId) {
92
+ return `/people/${currentCompanyId}`;
93
+ }
94
+
95
+ return '';
96
+ };
97
+
98
+ export const DefaultProvider = ({children, onBootstrapReady}) => {
99
+ const appType = String(APP_ENV.APP_TYPE || '').toUpperCase();
100
+ const isShopClientApp = appType === 'SHOP';
101
+ const themeStore = useStore('theme');
102
+ const getters = themeStore.getters;
103
+ const actions = themeStore.actions;
104
+ const authStore = useStore('auth');
105
+ const authGetters = authStore.getters;
106
+ const peopleStore = useStore('people');
107
+ const peopleGetters = peopleStore.getters;
108
+ const peopleActions = peopleStore.actions;
109
+
110
+ const deviceStore = useStore('device');
111
+ const deviceActions = deviceStore.actions;
112
+
113
+ const device_configStore = useStore('device_config');
114
+ const deviceConfigsGetters = device_configStore.getters;
115
+ const deviceConfigsActions = device_configStore.actions;
116
+
117
+ const configsStore = useStore('configs');
118
+ const configActions = configsStore.actions;
119
+ const configsGetters = configsStore.getters;
120
+ const printerStore = useStore('printer');
121
+ const printerActions = printerStore.actions;
122
+ const walletPaymentTypeStore = useStore('walletPaymentType');
123
+ const paymentTypeActions = walletPaymentTypeStore.actions;
124
+ const translateStore = useStore('translate');
125
+ const translateActions = translateStore.actions;
126
+ const {items: companyConfigs} = configsGetters;
127
+ const {colors, menus} = getters;
128
+ const {currentCompany, defaultCompany, companies} = peopleGetters;
129
+ const {item: device_config} = deviceConfigsGetters;
130
+ const {isLogged, sessionChecked, user} = authGetters;
131
+ const hasCurrentCompany =
132
+ !!currentCompany && Object.entries(currentCompany).length > 0;
133
+ const [translateReady, setTranslateReady] = useState(true);
134
+ const [deviceConfigFetched, setDeviceConfigFetched] = useState(false);
135
+ const [mainConfigsDiscovered, setMainConfigsDiscovered] = useState(false);
136
+ const [deviceRuntimeConfigSynced, setDeviceRuntimeConfigSynced] =
137
+ useState(false);
138
+ const [currentRouteName, setCurrentRouteName] = useState('');
139
+ const [appState, setAppState] = useState(AppState.currentState || 'active');
140
+ const [, setTranslateVersion] = useState(0);
141
+ const [baseThemeColors, setBaseThemeColors] = useState({});
142
+ const [bottomNavigationCount, setBottomNavigationCount] = useState(0);
143
+ const translateBootstrapKeyRef = useRef('');
144
+ const lastDeviceConfigPeopleIriRef = useRef('');
145
+ const [device, setDevice] = useState(
146
+ JSON.parse(localStorage.getItem('device') || '{}'),
147
+ );
148
+ const packageVersion = packageJson?.version || packageJson?.default?.version;
149
+ const appVersion = packageVersion || device?.appVersion;
150
+ const runtimeDeviceType = resolveOperationalDeviceType({
151
+ appType: APP_ENV.APP_TYPE,
152
+ deviceInfo: device || {},
153
+ });
154
+ const deviceConfigPeopleIri = resolveDeviceConfigPeopleIri({
155
+ appType,
156
+ currentCompany,
157
+ user,
158
+ });
159
+ const isPublicRouteActive = isPublicRoute(currentRouteName);
160
+ const shouldRunForegroundRealtimeServices =
161
+ Platform.OS !== 'android' || appState === 'active';
162
+ const registerBottomNavigation = useCallback(() => {
163
+ setBottomNavigationCount(current => current + 1);
164
+
165
+ let released = false;
166
+
167
+ return () => {
168
+ if (released) {
169
+ return;
170
+ }
171
+
172
+ released = true;
173
+ setBottomNavigationCount(current => Math.max(0, current - 1));
174
+ };
175
+ }, []);
176
+ const themeContextValue = useMemo(
177
+ () => ({
178
+ colors,
179
+ menus,
180
+ runtimeFooter: isShopClientApp
181
+ ? null
182
+ : {
183
+ appVersion,
184
+ colors,
185
+ defaultCompany,
186
+ device,
187
+ },
188
+ bottomChrome: {
189
+ hasBottomNavigation: bottomNavigationCount > 0,
190
+ registerBottomNavigation,
191
+ },
192
+ }),
193
+ [
194
+ appVersion,
195
+ bottomNavigationCount,
196
+ colors,
197
+ defaultCompany,
198
+ device,
199
+ isShopClientApp,
200
+ menus,
201
+ registerBottomNavigation,
202
+ ],
203
+ );
204
+ const runtimeBridges = (
205
+ <>
206
+ <LauncherModeBridge appState={appState} />
207
+ <KioskModeBridge appState={appState} />
208
+ <BackgroundRuntimeBridge appState={appState} />
209
+ <DeliveryPushBridge device={device} setDevice={setDevice} />
210
+ <ManagerPushBridge device={device} setDevice={setDevice} />
211
+ </>
212
+ );
213
+
214
+ useEffect(() => {
215
+ global.refreshTranslationsUI = () => {
216
+ setTranslateVersion(version => version + 1);
217
+ };
218
+
219
+ return () => {
220
+ if (global.refreshTranslationsUI) {
221
+ delete global.refreshTranslationsUI;
222
+ }
223
+ };
224
+ }, []);
225
+
226
+ useEffect(() => {
227
+ global.setRuntimeRouteName = routeName => {
228
+ const normalizedRouteName = String(routeName || '').trim();
229
+
230
+ setCurrentRouteName(previousRouteName =>
231
+ previousRouteName === normalizedRouteName
232
+ ? previousRouteName
233
+ : normalizedRouteName,
234
+ );
235
+ };
236
+
237
+ return () => {
238
+ if (global.setRuntimeRouteName) {
239
+ delete global.setRuntimeRouteName;
240
+ }
241
+ };
242
+ }, []);
243
+
244
+ useEffect(() => {
245
+ if (isLogged && !isPublicRouteActive) {
246
+ return;
247
+ }
248
+
249
+ setTranslateReady(true);
250
+ translateBootstrapKeyRef.current = '';
251
+ translateActions.setMessages({});
252
+ translateActions.setPendingMessages?.({});
253
+
254
+ if (global.t) {
255
+ delete global.t;
256
+ }
257
+ }, [isLogged, isPublicRouteActive]);
258
+
259
+ useEffect(() => {
260
+ const subscription = AppState.addEventListener('change', nextState => {
261
+ setAppState(nextState || 'active');
262
+ });
263
+
264
+ return () => {
265
+ subscription?.remove?.();
266
+ };
267
+ }, []);
268
+
269
+ const fetchDeviceId = async () => {
270
+ const uniqueId = await DeviceInfo.getUniqueId();
271
+ const deviceId = await DeviceInfo.getDeviceId();
272
+ const appName = DeviceInfo.getApplicationName();
273
+ const systemName = await DeviceInfo.getSystemName();
274
+ const systemVersion = await DeviceInfo.getSystemVersion();
275
+ const manufacturer = await DeviceInfo.getManufacturer();
276
+ const model = await DeviceInfo.getModel();
277
+ const batteryLevel = await DeviceInfo.getBatteryLevel();
278
+ const isEmulator = await DeviceInfo.isEmulator();
279
+ const appVersion = await DeviceInfo.getVersion();
280
+ const buildNumber = await DeviceInfo.getBuildNumber();
281
+ let ld = null;
282
+ if (uniqueId) {
283
+ ld = buildLocalRuntimeDevice({
284
+ appType: APP_ENV.APP_TYPE,
285
+ deviceInfo: {
286
+ id: uniqueId,
287
+ appName: appName,
288
+ deviceType: deviceId,
289
+ systemName: systemName,
290
+ systemVersion: systemVersion,
291
+ manufacturer: manufacturer,
292
+ model: model,
293
+ batteryLevel: batteryLevel,
294
+ isEmulator: isEmulator,
295
+ appVersion: appVersion,
296
+ buildNumber: buildNumber,
297
+ metadata: device?.metadata,
298
+ },
299
+ });
300
+ setDevice(ld);
301
+ localStorage.setItem('device', JSON.stringify(ld));
302
+ } else {
303
+ setTimeout(() => {
304
+ fetchDeviceId();
305
+ }, 300);
306
+ }
307
+ };
308
+ useEffect(() => {
309
+ const checkVersion = async () => {
310
+ const appVersion = await DeviceInfo.getVersion();
311
+ if (
312
+ device &&
313
+ ((device.appVersion && device.appVersion != appVersion) || !device.appName)
314
+ ) {
315
+ fetchDeviceId();
316
+ }
317
+ };
318
+ checkVersion();
319
+ }, [device]);
320
+
321
+ useEffect(() => {
322
+ if (!device || !device.id) {
323
+ fetchDeviceId();
324
+ } else {
325
+ deviceActions.setItem(device);
326
+ }
327
+ }, [device]);
328
+
329
+ useEffect(() => {
330
+ if (device && device.id) {
331
+ peopleActions.defaultCompany();
332
+ }
333
+ }, [device?.id]);
334
+
335
+ useEffect(() => {
336
+ if (
337
+ !deviceConfigPeopleIri ||
338
+ lastDeviceConfigPeopleIriRef.current === deviceConfigPeopleIri
339
+ ) {
340
+ return;
341
+ }
342
+
343
+ lastDeviceConfigPeopleIriRef.current = deviceConfigPeopleIri;
344
+ setDeviceConfigFetched(false);
345
+ setDeviceRuntimeConfigSynced(false);
346
+ deviceConfigsActions.setItem({});
347
+ }, [deviceConfigPeopleIri, deviceConfigsActions]);
348
+
349
+ useEffect(() => {
350
+ if (!sessionChecked || !isLogged || !deviceConfigPeopleIri || !device?.id || deviceConfigFetched) {
351
+ return;
352
+ }
353
+
354
+ let cancelled = false;
355
+
356
+ const syncDeviceRegistration = async () => {
357
+ const items = await deviceActions.getItems({
358
+ device: device.id,
359
+ people: deviceConfigPeopleIri,
360
+ type: runtimeDeviceType,
361
+ });
362
+
363
+ if (cancelled) {
364
+ return;
365
+ }
366
+
367
+ const existingDevice =
368
+ Array.isArray(items) && items.length > 0 ? items[0] : null;
369
+ const nextDevice = buildDeviceRegistrationPayload({
370
+ deviceInfo: device,
371
+ appType: APP_ENV.APP_TYPE,
372
+ existingDevice,
373
+ });
374
+
375
+ if (!hasDeviceRecordChanges({existingDevice, nextDevice})) {
376
+ const nextLocalDevice = {
377
+ ...device,
378
+ entityId: existingDevice?.id || device?.entityId || null,
379
+ entityIri:
380
+ existingDevice?.['@id'] ||
381
+ device?.entityIri ||
382
+ (existingDevice?.id ? `/devices/${existingDevice.id}` : null),
383
+ alias: existingDevice?.alias || nextDevice.alias,
384
+ type: device?.type || runtimeDeviceType,
385
+ metadata: {
386
+ ...(existingDevice?.metadata || {}),
387
+ ...(nextDevice.metadata || {}),
388
+ },
389
+ };
390
+
391
+ if (JSON.stringify(nextLocalDevice) !== JSON.stringify(device)) {
392
+ setDevice(nextLocalDevice);
393
+ localStorage.setItem('device', JSON.stringify(nextLocalDevice));
394
+ deviceActions.setItem(nextLocalDevice);
395
+ }
396
+ return;
397
+ }
398
+
399
+ const savedDevice = await deviceActions.save(nextDevice);
400
+ if (cancelled || !savedDevice) {
401
+ return;
402
+ }
403
+
404
+ const nextLocalDevice = {
405
+ ...device,
406
+ entityId: savedDevice?.id || device?.entityId || null,
407
+ entityIri:
408
+ savedDevice?.['@id'] ||
409
+ device?.entityIri ||
410
+ (savedDevice?.id ? `/devices/${savedDevice.id}` : null),
411
+ alias: savedDevice.alias || nextDevice.alias,
412
+ type: device?.type || runtimeDeviceType,
413
+ metadata: {
414
+ ...(savedDevice?.metadata || {}),
415
+ ...(nextDevice.metadata || {}),
416
+ },
417
+ };
418
+
419
+ if (JSON.stringify(nextLocalDevice) !== JSON.stringify(device)) {
420
+ setDevice(nextLocalDevice);
421
+ localStorage.setItem('device', JSON.stringify(nextLocalDevice));
422
+ deviceActions.setItem(nextLocalDevice);
423
+ }
424
+ };
425
+
426
+ syncDeviceRegistration().catch(() => {});
427
+
428
+ return () => {
429
+ cancelled = true;
430
+ };
431
+ }, [
432
+ device?.appVersion,
433
+ device?.batteryLevel,
434
+ device?.buildNumber,
435
+ device?.deviceType,
436
+ device?.id,
437
+ device?.metadata,
438
+ device?.manufacturer,
439
+ device?.model,
440
+ device?.systemVersion,
441
+ deviceConfigFetched,
442
+ deviceConfigPeopleIri,
443
+ isLogged,
444
+ sessionChecked,
445
+ runtimeDeviceType,
446
+ ]);
447
+
448
+ useEffect(() => {
449
+ if (isShopClientApp || !sessionChecked || !isLogged || !currentCompany?.id) {
450
+ return;
451
+ }
452
+
453
+ printerActions
454
+ .ensureCompanyPrintersLoaded({people: currentCompany.id})
455
+ .catch(() => {});
456
+ }, [currentCompany?.id, isLogged, isShopClientApp, printerActions, sessionChecked]);
457
+
458
+ useEffect(() => {
459
+ const paymentConfigSource = isShopClientApp
460
+ ? Object.keys(companyConfigs || {}).length > 0
461
+ ? companyConfigs
462
+ : currentCompany?.configs
463
+ : device_config?.configs;
464
+
465
+ if (!currentCompany?.id || !paymentConfigSource) {
466
+ paymentTypeActions.setItems([]);
467
+ return;
468
+ }
469
+
470
+ let isMounted = true;
471
+
472
+ api
473
+ .fetch('wallet_payment_types', {
474
+ params: {
475
+ people: `/people/${currentCompany.id}`,
476
+ },
477
+ })
478
+ .then(response => {
479
+ if (!isMounted) {
480
+ return;
481
+ }
482
+
483
+ const walletPaymentTypes = Array.isArray(response?.member)
484
+ ? response.member
485
+ : Array.isArray(response?.['hydra:member'])
486
+ ? response['hydra:member']
487
+ : Array.isArray(response)
488
+ ? response
489
+ : [];
490
+ const allowedPaymentTypeIds = resolveDevicePaymentTypeIds(
491
+ paymentConfigSource,
492
+ walletPaymentTypes,
493
+ );
494
+
495
+ paymentTypeActions.setItems(
496
+ filterWalletPaymentTypesByAllowedIds(
497
+ walletPaymentTypes,
498
+ allowedPaymentTypeIds,
499
+ ),
500
+ );
501
+ })
502
+ .catch(() => {
503
+ if (isMounted) {
504
+ paymentTypeActions.setItems([]);
505
+ }
506
+ });
507
+
508
+ return () => {
509
+ isMounted = false;
510
+ };
511
+ }, [
512
+ companyConfigs,
513
+ currentCompany?.configs,
514
+ currentCompany?.id,
515
+ device_config?.configs,
516
+ isShopClientApp,
517
+ paymentTypeActions,
518
+ ]);
519
+
520
+ useEffect(() => {
521
+ if (
522
+ device &&
523
+ device.id &&
524
+ isLogged &&
525
+ currentCompany &&
526
+ Object.entries(currentCompany).length > 0
527
+ ) {
528
+ setDeviceConfigFetched(false);
529
+ setDeviceRuntimeConfigSynced(false);
530
+ deviceConfigsActions
531
+ .getItems({
532
+ 'device.device': device.id,
533
+ people: '/people/' + currentCompany.id,
534
+ type: runtimeDeviceType,
535
+ })
536
+ .then(data => {
537
+ if (Array.isArray(data) && data.length > 0) {
538
+ const nextItem = {
539
+ ...data[0],
540
+ configs: parseConfigsObject(data[0]?.configs),
541
+ };
542
+ deviceConfigsActions.setItem(nextItem);
543
+ return;
544
+ }
545
+
546
+ deviceConfigsActions.setItem({});
547
+ })
548
+ .catch(() => {})
549
+ .finally(() => {
550
+ setDeviceConfigFetched(true);
551
+ });
552
+ }
553
+ }, [currentCompany?.id, isLogged, device?.id, runtimeDeviceType]);
554
+
555
+ useEffect(() => {
556
+ if (
557
+ !deviceConfigFetched ||
558
+ !isLogged ||
559
+ !deviceConfigPeopleIri ||
560
+ !device?.id ||
561
+ deviceRuntimeConfigSynced
562
+ ) {
563
+ return;
564
+ }
565
+
566
+ const {nextConfigs, needsUpdate} = buildProviderManagedDeviceConfigs({
567
+ configs: device_config?.configs,
568
+ appVersion,
569
+ deviceInfo: device,
570
+ });
571
+
572
+ if (!needsUpdate) {
573
+ setDeviceRuntimeConfigSynced(true);
574
+ return;
575
+ }
576
+
577
+ deviceConfigsActions
578
+ .addDeviceConfigs({
579
+ device: device.id,
580
+ configs: JSON.stringify(nextConfigs),
581
+ people: deviceConfigPeopleIri,
582
+ type: runtimeDeviceType,
583
+ })
584
+ .catch(() => {})
585
+ .finally(() => {
586
+ setDeviceRuntimeConfigSynced(true);
587
+ });
588
+ }, [
589
+ appVersion,
590
+ currentCompany?.id,
591
+ device?.id,
592
+ device?.manufacturer,
593
+ device?.isEmulator,
594
+ deviceConfigFetched,
595
+ deviceConfigPeopleIri,
596
+ deviceRuntimeConfigSynced,
597
+ deviceConfigsActions,
598
+ device_config?.configs,
599
+ isLogged,
600
+ runtimeDeviceType,
601
+ ]);
602
+
603
+ useEffect(() => {
604
+ if (!isLogged || !currentCompany?.id || !device?.id) {
605
+ return;
606
+ }
607
+
608
+ setMainConfigsDiscovered(false);
609
+ }, [isLogged, currentCompany?.id, device?.id]);
610
+
611
+ useEffect(() => {
612
+ if (
613
+ !isLogged ||
614
+ !currentCompany?.id ||
615
+ !device?.id ||
616
+ mainConfigsDiscovered
617
+ ) {
618
+ return;
619
+ }
620
+
621
+ configActions
622
+ .discoveryMainConfigs({
623
+ people: '/people/' + currentCompany.id,
624
+ })
625
+ .catch(() => {})
626
+ .finally(() => {
627
+ setMainConfigsDiscovered(true);
628
+ });
629
+ }, [configActions, currentCompany?.id, device?.id, isLogged, mainConfigsDiscovered]);
630
+
631
+ useEffect(() => {
632
+ if (
633
+ isLogged &&
634
+ currentCompany &&
635
+ Object.entries(currentCompany).length > 0 &&
636
+ !mainConfigsDiscovered
637
+ ) {
638
+ configActions.setItems(currentCompany.configs);
639
+ }
640
+ }, [currentCompany, isLogged, mainConfigsDiscovered]);
641
+
642
+ useEffect(() => {
643
+ if (
644
+ !currentRouteName ||
645
+ isPublicRouteActive
646
+ ) {
647
+ return;
648
+ }
649
+
650
+ if (
651
+ !isLogged ||
652
+ !currentCompany ||
653
+ Object.entries(currentCompany).length === 0 ||
654
+ !deviceConfigFetched
655
+ ) {
656
+ return;
657
+ }
658
+
659
+ const currentConfig = JSON.parse(localStorage.getItem('config') || '{}');
660
+ const sessionData = JSON.parse(localStorage.getItem('session') || '{}');
661
+ const currentCompanyId = normalizeEntityId(currentCompany?.id);
662
+ const defaultCompanyId = normalizeEntityId(defaultCompany?.id);
663
+ const configuredLanguage = resolveConfiguredLanguage({
664
+ currentCompany,
665
+ defaultCompany,
666
+ currentConfig,
667
+ sessionData,
668
+ });
669
+ const nextTranslateBootstrapKey = [
670
+ configuredLanguage,
671
+ currentCompanyId,
672
+ defaultCompanyId,
673
+ ].join('::');
674
+
675
+ if (translateBootstrapKeyRef.current === nextTranslateBootstrapKey) {
676
+ if (global.t) {
677
+ global.t.companies = companies;
678
+ global.t.currentCompany = currentCompany;
679
+ global.t.defaultCompany = defaultCompany;
680
+ }
681
+
682
+ return;
683
+ }
684
+
685
+ if (currentConfig.language !== configuredLanguage) {
686
+ const nextConfig = {...currentConfig, language: configuredLanguage};
687
+ localStorage.setItem(
688
+ 'config',
689
+ JSON.stringify(nextConfig),
690
+ );
691
+ }
692
+
693
+ translateBootstrapKeyRef.current = nextTranslateBootstrapKey;
694
+ global.t = new Translate(
695
+ companies,
696
+ defaultCompany,
697
+ currentCompany,
698
+ Object.keys(stores),
699
+ translateStore,
700
+ );
701
+ setTranslateReady(true);
702
+ global.refreshTranslationsUI?.();
703
+ global.t.discoveryAll().catch(() => {});
704
+ }, [
705
+ companies,
706
+ currentCompany,
707
+ currentRouteName,
708
+ defaultCompany,
709
+ deviceConfigFetched,
710
+ isLogged,
711
+ isPublicRouteActive,
712
+ translateActions,
713
+ ]);
714
+
715
+
716
+ useEffect(() => {
717
+ if (!isLogged || translateReady || !hasCurrentCompany) {
718
+ onBootstrapReady?.();
719
+ }
720
+ }, [isLogged, translateReady, hasCurrentCompany, onBootstrapReady]);
721
+
722
+
723
+ useEffect(() => {
724
+ if (
725
+ device &&
726
+ device.id &&
727
+ isLogged
728
+ ) {
729
+ peopleActions.myCompanies();
730
+ }
731
+ }, [isLogged, device?.id]);
732
+
733
+ useEffect(() => {
734
+ const fetchColors = async () => {
735
+ const appDomain = resolveAppDomain(APP_ENV.DOMAIN);
736
+ const params = appDomain ? {'app-domain': appDomain} : undefined;
737
+
738
+ try {
739
+ const cssText = await api.fetch('themes-colors.css', {
740
+ responseType: 'text',
741
+ params,
742
+ });
743
+ const parsedColors = parseThemeCss(cssText);
744
+ setBaseThemeColors(parsedColors);
745
+ actions.setColors(parsedColors);
746
+ } catch {
747
+ setBaseThemeColors({});
748
+ }
749
+ };
750
+
751
+ if (device?.id) {
752
+ fetchColors();
753
+ }
754
+ }, [actions, currentCompany?.id, defaultCompany?.id, device?.id]);
755
+
756
+ useEffect(() => {
757
+ if (!isLogged || !currentCompany?.id || !appType) {
758
+ actions.setMenus([]);
759
+ return;
760
+ }
761
+
762
+ let cancelled = false;
763
+
764
+ api
765
+ .fetch('menus-people', {
766
+ params: {
767
+ myCompany: currentCompany.id,
768
+ appType,
769
+ menuType: 'home',
770
+ },
771
+ })
772
+ .then(result => {
773
+ if (!cancelled) {
774
+ actions.setMenus(normalizeRuntimeMenuResponse(result, {appType}));
775
+ }
776
+ })
777
+ .catch(() => {
778
+ if (!cancelled) {
779
+ actions.setMenus(normalizeRuntimeMenuResponse(null, {appType}));
780
+ }
781
+ });
782
+
783
+ return () => {
784
+ cancelled = true;
785
+ };
786
+ }, [actions, appType, currentCompany?.id, isLogged]);
787
+
788
+ useEffect(() => {
789
+ const companyThemeColors =
790
+ currentCompany?.theme?.colors || defaultCompany?.theme?.colors || {};
791
+ const mergedThemeColors = {
792
+ ...(baseThemeColors || {}),
793
+ ...(companyThemeColors || {}),
794
+ };
795
+
796
+ const palette = resolveThemePalette(mergedThemeColors, runtimeColors);
797
+ applyPaletteToRuntimeColors(palette, runtimeColors);
798
+ applyThemeCssVariables({
799
+ themeColors: mergedThemeColors,
800
+ palette,
801
+ });
802
+
803
+ actions.setColors(mergedThemeColors);
804
+ }, [actions, baseThemeColors, currentCompany?.id, currentCompany?.theme?.colors]);
805
+ return (
806
+ <>
807
+ {runtimeBridges}
808
+ {device &&
809
+ device.id && (
810
+ <ThemeContext.Provider value={themeContextValue}>
811
+ <View
812
+ style={[
813
+ providerStyles.shell,
814
+ {
815
+ backgroundColor: colors?.background || runtimeColors.background,
816
+ },
817
+ ]}>
818
+ <View style={providerStyles.content}>{children}</View>
819
+ {!isShopClientApp && bottomNavigationCount === 0 && (
820
+ <RuntimeInfoFooter
821
+ appVersion={appVersion}
822
+ defaultCompany={defaultCompany}
823
+ device={device}
824
+ colors={colors}
825
+ />
826
+ )}
827
+ </View>
828
+ {!isShopClientApp && (
829
+ <>
830
+ {shouldRunForegroundRealtimeServices && (
831
+ <>
832
+ <WebsocketListener />
833
+ <DeviceAlertSoundService />
834
+ <ProductCatalogCacheService />
835
+ <RemoteCheckoutService />
836
+ <PrintService />
837
+ </>
838
+ )}
839
+ </>
840
+ )}
841
+ </ThemeContext.Provider>
842
+ )}
843
+ </>
844
+ );
845
+ };
846
+
847
+ export const useTheme = () => useContext(ThemeContext);
848
+ // TODO(store-first): quando este arquivo for mexido, mover a leitura para stores, remover api.fetch e evitar repassar dados em objetos quando o store ja resolver isso.