@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,620 @@
1
+ const TRANSLATES_STORAGE_KEY = "translates";
2
+
3
+ export default class Translate {
4
+ constructor(companies, defaultCompany, currentCompany, stores, translateStore) {
5
+ this.translates = this.loadStorageObject(TRANSLATES_STORAGE_KEY);
6
+
7
+ this.language = this.normalizeLanguageCode(
8
+ JSON.parse(localStorage.getItem("config") || "{}").language
9
+ ) || "pt-br";
10
+
11
+ this.defaultCompany = defaultCompany;
12
+ this.currentCompany = currentCompany;
13
+ this.translateStore = translateStore || {};
14
+ this.translateActions = this.translateStore?.actions || {};
15
+ this.companies = companies;
16
+ this.stores = stores;
17
+ this.bootstrapStores = new Set(this.getStoreList());
18
+ this.discoveredStores = new Set();
19
+ this.pendingStoreDiscoveries = new Map();
20
+ this.pendingPersistRequests = new Map();
21
+ this.t = this.t.bind(this);
22
+ if (typeof this.translateActions?.setPendingMessages === "function") {
23
+ this.translateActions.setPendingMessages({});
24
+ }
25
+ this.syncCachedMessagesToStore();
26
+ this.hydrateDiscoveredStores();
27
+ }
28
+
29
+ loadStorageObject(key) {
30
+ if (typeof localStorage === "undefined") {
31
+ return {};
32
+ }
33
+
34
+ try {
35
+ const value = localStorage.getItem(key);
36
+ if (!value) return {};
37
+
38
+ const parsed = JSON.parse(value);
39
+ return parsed && typeof parsed === "object" ? parsed : {};
40
+ } catch {
41
+ return {};
42
+ }
43
+ }
44
+
45
+ getLanguageBucket(language = this.language, createIfMissing = false) {
46
+ const normalizedLanguage = this.normalizeLanguageCode(language);
47
+ if (!normalizedLanguage) return null;
48
+
49
+ if (!this.translates[normalizedLanguage] && createIfMissing) {
50
+ this.translates[normalizedLanguage] = {};
51
+ }
52
+
53
+ return this.translates[normalizedLanguage] || null;
54
+ }
55
+
56
+ getCompanyBucket(companyId, createIfMissing = false, language = this.language) {
57
+ const normalizedCompanyId = this.normalizeId(companyId);
58
+ if (!normalizedCompanyId) return null;
59
+
60
+ const languageBucket = this.getLanguageBucket(language, createIfMissing);
61
+ if (!languageBucket) return null;
62
+
63
+ if (!languageBucket.companies && createIfMissing) {
64
+ languageBucket.companies = {};
65
+ }
66
+
67
+ if (
68
+ createIfMissing &&
69
+ languageBucket.companies &&
70
+ !languageBucket.companies[normalizedCompanyId]
71
+ ) {
72
+ languageBucket.companies[normalizedCompanyId] = {};
73
+ }
74
+
75
+ return languageBucket.companies?.[normalizedCompanyId] || null;
76
+ }
77
+
78
+ getStoreBucket(companyId, store, createIfMissing = false, language = this.language) {
79
+ if (!store) return null;
80
+
81
+ if (companyId) {
82
+ const companyBucket = this.getCompanyBucket(companyId, createIfMissing, language);
83
+ if (!companyBucket) return null;
84
+
85
+ if (createIfMissing && !companyBucket[store]) {
86
+ companyBucket[store] = {};
87
+ }
88
+
89
+ return companyBucket[store] || null;
90
+ }
91
+
92
+ const languageBucket = this.getLanguageBucket(language, createIfMissing);
93
+ if (!languageBucket) return null;
94
+
95
+ if (createIfMissing && !languageBucket[store]) {
96
+ languageBucket[store] = {};
97
+ }
98
+
99
+ return languageBucket[store] || null;
100
+ }
101
+
102
+ normalizeId(value) {
103
+ if (value == null) return null;
104
+
105
+ const match = String(value).match(/\d+/);
106
+ return match?.[0] || null;
107
+ }
108
+
109
+ normalizeLanguageCode(value) {
110
+ if (typeof value !== "string") return "";
111
+
112
+ return value.trim().replace(/_/g, "-").toLowerCase();
113
+ }
114
+
115
+ getCompaniesToCache() {
116
+ const candidates = [
117
+ this.defaultCompany,
118
+ this.currentCompany,
119
+ ].filter((company) => company?.id);
120
+
121
+ const unique = [];
122
+ const seen = new Set();
123
+
124
+ candidates.forEach((company) => {
125
+ const companyId = this.normalizeId(company.id);
126
+ if (!companyId || seen.has(companyId)) return;
127
+
128
+ seen.add(companyId);
129
+ unique.push(company);
130
+ });
131
+
132
+ return unique;
133
+ }
134
+
135
+ getStoreList() {
136
+ if (Array.isArray(this.stores)) {
137
+ return this.stores.filter(Boolean);
138
+ }
139
+
140
+ return this.stores ? [this.stores] : [];
141
+ }
142
+
143
+ getPendingMessages() {
144
+ const messages = this.translateStore?.getters?.pendingMessages;
145
+ if (!messages || typeof messages !== "object" || Array.isArray(messages)) {
146
+ return {};
147
+ }
148
+
149
+ return messages;
150
+ }
151
+
152
+ getPendingLanguageBucket(language = this.language) {
153
+ const pendingMessages = this.getPendingMessages();
154
+ const normalizedLanguage = this.normalizeLanguageCode(language);
155
+ if (!normalizedLanguage) return null;
156
+
157
+ return pendingMessages[normalizedLanguage] || null;
158
+ }
159
+
160
+ getPendingCompanyBucket(companyId, language = this.language) {
161
+ const normalizedCompanyId = this.normalizeId(companyId);
162
+ if (!normalizedCompanyId) return null;
163
+
164
+ const languageBucket = this.getPendingLanguageBucket(language);
165
+ if (!languageBucket) return null;
166
+
167
+ const companiesBucket = languageBucket.companies;
168
+ if (!companiesBucket || typeof companiesBucket !== "object") {
169
+ return null;
170
+ }
171
+
172
+ return companiesBucket[normalizedCompanyId] || null;
173
+ }
174
+
175
+ getPendingStoreBucket(companyId, store, language = this.language) {
176
+ const normalizedStore = String(store || "").trim();
177
+ if (!normalizedStore) return null;
178
+
179
+ const companyBucket = this.getPendingCompanyBucket(companyId, language);
180
+ if (!companyBucket) return null;
181
+
182
+ return companyBucket[normalizedStore] || null;
183
+ }
184
+
185
+ hasPendingTranslate(store, type, key) {
186
+ const pendingStoreBucket = this.getPendingStoreBucket(
187
+ this.defaultCompany?.id,
188
+ store,
189
+ this.language,
190
+ );
191
+
192
+ return Boolean(pendingStoreBucket?.[type]?.[key]);
193
+ }
194
+
195
+ getStoreDiscoveryToken(store) {
196
+ return [
197
+ this.language,
198
+ String(store || ""),
199
+ ].join("::");
200
+ }
201
+
202
+ canDiscoverStore() {
203
+ return typeof this.translateActions?.getItems === "function";
204
+ }
205
+
206
+ hasCachedBootstrapStore(store) {
207
+ if (!store) return false;
208
+
209
+ const companies = this.getCompaniesToCache();
210
+ if (companies.length === 0) return false;
211
+
212
+ return companies.every((company) => this.getStoreBucket(company.id, store) != null);
213
+ }
214
+
215
+ hydrateDiscoveredStores() {
216
+ this.bootstrapStores.forEach((store) => {
217
+ if (this.hasCachedBootstrapStore(store)) {
218
+ this.markStoreDiscovered(store);
219
+ }
220
+ });
221
+ }
222
+
223
+ hasDiscoveredStore(store) {
224
+ if (!store) return false;
225
+
226
+ return this.discoveredStores.has(this.getStoreDiscoveryToken(store));
227
+ }
228
+
229
+ markStoreDiscovered(store) {
230
+ if (!store) return;
231
+
232
+ this.discoveredStores.add(this.getStoreDiscoveryToken(store));
233
+ }
234
+
235
+ ensureStoreDiscovered(store) {
236
+ if (!store || !this.canDiscoverStore()) {
237
+ return Promise.resolve(this.translates);
238
+ }
239
+
240
+ if (this.hasDiscoveredStore(store)) {
241
+ return Promise.resolve(this.translates);
242
+ }
243
+
244
+ const token = this.getStoreDiscoveryToken(store);
245
+ if (this.pendingStoreDiscoveries.has(token)) {
246
+ return this.pendingStoreDiscoveries.get(token);
247
+ }
248
+
249
+ const discoveryPromise = Promise.resolve()
250
+ .then(() => this.discoveryStoreTranslate(store))
251
+ .finally(() => {
252
+ this.pendingStoreDiscoveries.delete(token);
253
+ });
254
+
255
+ this.pendingStoreDiscoveries.set(token, discoveryPromise);
256
+
257
+ return discoveryPromise;
258
+ }
259
+
260
+ notifyTranslationsUpdated() {
261
+ const globalObject =
262
+ typeof global !== "undefined" ? global : globalThis;
263
+
264
+ if (typeof globalObject?.refreshTranslationsUI === "function") {
265
+ globalObject.refreshTranslationsUI();
266
+ }
267
+ }
268
+
269
+ syncCachedMessagesToStore() {
270
+ if (typeof this.translateActions?.setMessages !== "function") {
271
+ return;
272
+ }
273
+
274
+ this.translateActions.setMessages({
275
+ ...this.translates,
276
+ });
277
+ }
278
+
279
+ getPersistRequestToken(store, type, key) {
280
+ return [
281
+ this.language,
282
+ this.normalizeId(this.defaultCompany?.id),
283
+ String(store || "").trim(),
284
+ String(type || "").trim(),
285
+ String(key || "").trim(),
286
+ ].join("::");
287
+ }
288
+
289
+ resolveReferenceId(value) {
290
+ if (!value) return null;
291
+
292
+ if (typeof value === "object") {
293
+ return this.normalizeId(value.id || value["@id"] || value.people || value.language);
294
+ }
295
+
296
+ return this.normalizeId(value);
297
+ }
298
+
299
+ cacheTranslateRecord(record, fallbackCompanyId = null, fallbackLanguage = this.language) {
300
+ const companyId = this.resolveReferenceId(record?.people) || this.normalizeId(fallbackCompanyId);
301
+ const language =
302
+ this.normalizeLanguageCode(record?.language?.language || record?.language?.locale || fallbackLanguage) ||
303
+ this.language;
304
+ const store = String(record?.store || "").trim();
305
+ const type = String(record?.type || "").trim();
306
+ const key = String(record?.key || "").trim();
307
+ const message = record?.translate ?? this.formatMessage(key);
308
+
309
+ if (!companyId || !store || !type || !key) {
310
+ return false;
311
+ }
312
+
313
+ const previousMessage = this.getStoreBucket(companyId, store, false, language)?.[type]?.[key];
314
+ this.findMessage(store, type, key, message, companyId, language);
315
+
316
+ return previousMessage !== message;
317
+ }
318
+
319
+ getMessageFromBuckets(store, type, key) {
320
+ const companyIds = [
321
+ this.currentCompany?.id,
322
+ this.defaultCompany?.id,
323
+ ]
324
+ .map((value) => this.normalizeId(value))
325
+ .filter(Boolean);
326
+
327
+ for (const companyId of companyIds) {
328
+ const companyMessage =
329
+ this.getStoreBucket(companyId, store)?.[type]?.[key];
330
+
331
+ if (companyMessage) {
332
+ return companyMessage;
333
+ }
334
+ }
335
+
336
+ return this.getStoreBucket(null, store)?.[type]?.[key];
337
+ }
338
+
339
+ persistMissingTranslate(store, type, key, translate) {
340
+ if (!store || !type || !key || !this.defaultCompany?.id) return;
341
+
342
+ // verifica se tenho acesso ao defaultCompany
343
+ const defaultCompanyId = this.normalizeId(this.defaultCompany?.id);
344
+ if (
345
+ !Array.isArray(this.companies) ||
346
+ !this.companies.some((company) => this.normalizeId(company?.id) === defaultCompanyId)
347
+ )
348
+ return;
349
+
350
+ if (this.hasPendingTranslate(store, type, key)) {
351
+ return;
352
+ }
353
+
354
+ const requestToken = this.getPersistRequestToken(store, type, key);
355
+ if (this.pendingPersistRequests.has(requestToken)) {
356
+ return;
357
+ }
358
+
359
+ if (
360
+ typeof this.translateActions?.queueMissingTranslate !== "function" ||
361
+ typeof this.translateActions?.save !== "function"
362
+ ) {
363
+ return;
364
+ }
365
+
366
+ this.translateActions.queueMissingTranslate({
367
+ language: this.language,
368
+ companyId: this.defaultCompany.id,
369
+ store,
370
+ type,
371
+ key,
372
+ translate,
373
+ });
374
+
375
+ const request = Promise.resolve(
376
+ this.translateActions.save({
377
+ people: "/people/" + defaultCompanyId,
378
+ language: this.language,
379
+ store,
380
+ type,
381
+ key,
382
+ translate,
383
+ revised: false,
384
+ })
385
+ )
386
+ .then((result) => {
387
+ const changed = this.cacheTranslateRecord(result, defaultCompanyId, this.language);
388
+ this.removePendingTranslate(store, type, key);
389
+ this.persist();
390
+ if (changed) {
391
+ this.notifyTranslationsUpdated();
392
+ }
393
+ return result;
394
+ })
395
+ .catch(() => {})
396
+ .finally(() => {
397
+ this.pendingPersistRequests.delete(requestToken);
398
+ });
399
+
400
+ this.pendingPersistRequests.set(requestToken, request);
401
+ }
402
+
403
+ removePendingTranslate(store, type, key) {
404
+ if (!store || !type || !key || !this.defaultCompany?.id) return;
405
+
406
+ if (typeof this.translateActions?.removePendingTranslate !== "function") {
407
+ return;
408
+ }
409
+
410
+ this.translateActions.removePendingTranslate({
411
+ language: this.language,
412
+ companyId: this.defaultCompany.id,
413
+ store,
414
+ type,
415
+ key,
416
+ });
417
+ }
418
+
419
+ t(store, type, key) {
420
+ const translate = this.getMessageFromBuckets(store, type, key);
421
+ const fallbackTranslate = this.formatMessage(key);
422
+ const shouldDiscoverStore =
423
+ this.canDiscoverStore() && !this.hasDiscoveredStore(store);
424
+
425
+ if (shouldDiscoverStore) {
426
+ this.ensureStoreDiscovered(store)
427
+ .then(() => {
428
+ const discoveredTranslate = this.getMessageFromBuckets(store, type, key);
429
+
430
+ if (discoveredTranslate) {
431
+ return;
432
+ }
433
+
434
+ this.persistMissingTranslate(store, type, key, fallbackTranslate);
435
+ })
436
+ .catch(() => {});
437
+ }
438
+
439
+ if (!translate) {
440
+ if (!shouldDiscoverStore) {
441
+ this.persistMissingTranslate(store, type, key, fallbackTranslate);
442
+ }
443
+
444
+ return fallbackTranslate;
445
+ }
446
+
447
+ return translate;
448
+ }
449
+
450
+ reload() {
451
+ this.clear();
452
+ return this.discoveryAll({ force: true });
453
+ }
454
+
455
+ clear() {
456
+ this.translates = {};
457
+ this.discoveredStores.clear();
458
+ this.pendingStoreDiscoveries.clear();
459
+ this.pendingPersistRequests.clear();
460
+ if (typeof this.translateActions?.setPendingMessages === "function") {
461
+ this.translateActions.setPendingMessages({});
462
+ }
463
+ this.persist();
464
+ }
465
+
466
+ shouldFetchStoreForCompany(store, company, force = false) {
467
+ if (force) return true;
468
+
469
+ const companyId = this.normalizeId(company?.id);
470
+ if (!companyId || !store) return false;
471
+
472
+ const storeBucket = this.getStoreBucket(companyId, store, false, this.language);
473
+ return storeBucket == null;
474
+ }
475
+
476
+ async discoveryAll(options = {}) {
477
+ const companies = this.getCompaniesToCache();
478
+
479
+ for (const company of companies) {
480
+ for (const store of this.getStoreList()) {
481
+ await this.discoveryStoreTranslate(store, {
482
+ ...options,
483
+ companies: [company],
484
+ });
485
+ }
486
+ }
487
+
488
+ return this.translates;
489
+ }
490
+
491
+ async discoveryStoreTranslate(store, options = {}) {
492
+ if (!store) return this.translates;
493
+
494
+ const force = options.force === true;
495
+ if (!force && this.hasDiscoveredStore(store)) {
496
+ return this.translates;
497
+ }
498
+
499
+ const companies = Array.isArray(options.companies) && options.companies.length > 0
500
+ ? options.companies
501
+ : this.getCompaniesToCache();
502
+ if (companies.length === 0) {
503
+ this.markStoreDiscovered(store);
504
+ return this.translates;
505
+ }
506
+
507
+ let hasChanges = false;
508
+ for (const company of companies) {
509
+ const changed = await this.fetchTranslates(store, company, { force });
510
+ hasChanges = changed || hasChanges;
511
+ }
512
+
513
+ if (this.hasCachedBootstrapStore(store)) {
514
+ this.markStoreDiscovered(store);
515
+ }
516
+
517
+ if (hasChanges) {
518
+ this.persist();
519
+ this.notifyTranslationsUpdated();
520
+ }
521
+
522
+ return this.translates;
523
+ }
524
+
525
+ async fetchTranslates(store, company, options = {}) {
526
+ if (!company?.id) return false;
527
+
528
+ const force = options.force === true;
529
+ if (!this.shouldFetchStoreForCompany(store, company, force)) {
530
+ return false;
531
+ }
532
+
533
+ const params = {
534
+ store: store,
535
+ "language.language": this.language,
536
+ people: "/people/" + company.id,
537
+ };
538
+
539
+ const storeTranslates = [];
540
+ let page = 1;
541
+ let firstPageSize = null;
542
+ const maxPages = 1000;
543
+
544
+ while (page <= maxPages) {
545
+ const pageItems = await this.translateActions.getItems({
546
+ ...params,
547
+ page,
548
+ });
549
+
550
+ if (!Array.isArray(pageItems) || pageItems.length === 0) break;
551
+
552
+ storeTranslates.push(...pageItems);
553
+ if (firstPageSize == null) firstPageSize = pageItems.length;
554
+ if (pageItems.length < firstPageSize) break;
555
+
556
+ page += 1;
557
+ }
558
+
559
+ const companyId = this.normalizeId(company?.id);
560
+ const storeBucket = this.getStoreBucket(companyId, store, true);
561
+ let changed = false;
562
+
563
+ if (storeBucket) {
564
+ if (Object.keys(storeBucket).length > 0) {
565
+ changed = true;
566
+ }
567
+ Object.keys(storeBucket).forEach((type) => {
568
+ delete storeBucket[type];
569
+ });
570
+ }
571
+
572
+ storeTranslates.forEach((element) => {
573
+ changed = this.cacheTranslateRecord(
574
+ {
575
+ ...element,
576
+ people: element.people || companyId,
577
+ },
578
+ companyId,
579
+ this.language,
580
+ ) || changed;
581
+ this.removePendingTranslate(element.store, element.type, element.key);
582
+ });
583
+
584
+ return changed || storeTranslates.length === 0;
585
+ }
586
+
587
+ persist() {
588
+ if (typeof localStorage !== "undefined") {
589
+ localStorage.setItem("translates", JSON.stringify(this.translates));
590
+ }
591
+
592
+ this.syncCachedMessagesToStore();
593
+ }
594
+
595
+ findMessage(store, type, key, message, companyId = null, language = this.language) {
596
+ const storeBucket = this.getStoreBucket(companyId, store, true, language);
597
+ if (!storeBucket) {
598
+ return this.formatMessage(key);
599
+ }
600
+
601
+ if (!storeBucket[type]) {
602
+ storeBucket[type] = {};
603
+ }
604
+
605
+ if (message !== null)
606
+ storeBucket[type][key] = message;
607
+
608
+ return storeBucket[type][key] || this.formatMessage(key);
609
+ }
610
+
611
+ formatMessage(key) {
612
+ if (!key) return "";
613
+
614
+ return key
615
+ .replace(/([a-z])([A-Z])/g, "$1_$2")
616
+ .replace(/_/g, " ")
617
+ .replace(/-/g, " ")
618
+ .replace(/^\w/, (c) => c.toUpperCase());
619
+ }
620
+ }