@controleonline/ui-common 1.2.71 → 1.2.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/actions/workers/manager/action.yml +147 -0
- package/.github/actions/workers/qa/action.yml +44 -0
- package/.github/actions/workers/security/action.yml +44 -0
- package/.github/actions/workers/technical-documenter/action.yml +51 -0
- package/.github/workflows/manager-worker.yml +168 -0
- package/.github/workflows/publish-npm.yml +45 -0
- package/.gitmodules +3 -0
- package/AGENTS.md +6 -0
- package/README.md +14 -0
- package/package.json +3 -2
- package/src/api/fetch.js +1 -1
- package/src/api/index.js +92 -22
- package/src/react/components/AddImportModal.js +94 -110
- package/src/react/components/BottomNavigationBar.config.js +211 -231
- package/src/react/components/CategoryForm.js +52 -35
- package/src/react/components/DefaultProvider.native.js +131 -95
- package/src/react/components/DefaultProvider.web.js +148 -74
- package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
- package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
- package/src/react/components/RuntimeInfoFooter.js +100 -36
- package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
- package/src/react/components/UnifiedPaymentBar.js +7 -4
- package/src/react/components/UserAvatar.js +160 -0
- package/src/react/components/integrations/IntegrationHero/index.js +48 -0
- package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
- package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
- package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
- package/src/react/config/deviceConfigBootstrap.js +5 -3
- package/src/react/pages/Connections.js +229 -0
- package/src/react/pages/Connections.styles.js +222 -0
- package/src/react/pages/DeviceDetailPage.js +2814 -0
- package/src/react/pages/DeviceDetailPage.styles.js +308 -0
- package/src/react/pages/Devices/currentDevice.js +194 -0
- package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
- package/src/react/pages/Devices/deviceTypes/all.js +23 -0
- package/src/react/pages/Devices/deviceTypes/device.js +25 -0
- package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
- package/src/react/pages/Devices/deviceTypes/display.js +26 -0
- package/src/react/pages/Devices/deviceTypes/index.js +145 -0
- package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
- package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
- package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
- package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
- package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
- package/src/react/pages/Devices.js +183 -0
- package/src/react/pages/Devices.styles.js +353 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
- package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
- package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
- package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
- package/src/react/pages/Food99IntegrationPage.js +1 -0
- package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
- package/src/react/pages/GenericLogPage.js +42 -167
- package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
- package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
- package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
- package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
- package/src/react/pages/IFoodIntegrationPage.js +1 -0
- package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
- package/src/react/pages/Imports.js +214 -166
- package/src/react/pages/IntegrationConfigPage.js +744 -0
- package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
- package/src/react/pages/Integrations.js +299 -0
- package/src/react/pages/Integrations.styles.js +130 -0
- package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
- package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
- package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
- package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
- package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
- package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
- package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
- package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
- package/src/react/pages/PrinterDeviceFormPage.js +521 -0
- package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
- package/src/react/pages/WhatsAppConnectionPage.js +459 -0
- package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
- package/src/react/pages/integrationsCatalog.js +399 -0
- package/src/react/services/Cielo/Cielo.js +193 -193
- package/src/react/utils/categoryContexts.js +46 -0
- package/src/react/utils/entityDisplay.js +222 -217
- package/src/react/utils/fileUrl.js +39 -20
- package/src/react/utils/integrationPage.js +16 -0
- package/src/react/utils/runtimeFooter.js +40 -22
- package/src/react/utils/runtimeLanguage.js +50 -9
- package/src/react/utils/runtimeMenu.js +191 -131
- package/src/react/utils/runtimeZoom.js +43 -0
- package/src/react/utils/shopConfig.js +27 -15
- package/src/react/utils/shopFranchises.js +126 -1
- package/src/react/utils/storeColumns.js +23 -4
- package/src/react/utils/userAvatar.js +104 -0
- package/src/store/categories/index.js +48 -20
- package/src/store/device_config/index.js +62 -21
- package/src/store/entity_log/index.js +22 -1
- package/src/store/imports/customActions.js +51 -0
- package/src/store/imports/index.js +89 -88
- package/src/store/status/index.js +11 -11
- package/src/store/themes/index.js +22 -0
- package/src/store/timezones/index.js +3 -1
- package/src/tests/browser/manager/connections.spec.js +143 -0
- package/src/tests/browser/manager/devices-current.spec.js +343 -0
- package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
- package/src/tests/react/api/deviceHeaders.test.js +114 -0
- package/src/tests/react/components/AddImportModal.test.js +166 -0
- package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
- package/src/tests/react/components/UserAvatar.test.js +52 -0
- package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
- package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
- package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
- package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
- package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
- package/src/tests/react/services/Cielo.test.js +190 -190
- package/src/tests/react/store/categoriesOrdering.test.js +26 -0
- package/src/tests/react/utils/appDomain.test.js +62 -0
- package/src/tests/react/utils/entityDisplay.test.js +2 -2
- package/src/tests/react/utils/fileUrl.test.js +3 -3
- package/src/tests/react/utils/formatter.test.mjs +33 -0
- package/src/tests/react/utils/runtimeFooter.test.js +29 -4
- package/src/tests/react/utils/runtimeLanguage.test.js +79 -9
- package/src/tests/react/utils/runtimeMenu.test.js +198 -134
- package/src/tests/react/utils/runtimeZoom.test.js +38 -0
- package/src/tests/react/utils/shopConfig.test.js +10 -9
- package/src/tests/react/utils/shopFranchises.test.js +43 -0
- package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
- package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
- package/src/tests/react/utils/translate.test.mjs +141 -349
- package/src/tests/react/utils/userAvatar.test.js +63 -0
- package/src/utils/appDomain.js +15 -4
- package/src/utils/formatter.js +104 -16
- package/src/utils/integrationConfigs.js +80 -80
- package/src/utils/translate.js +222 -438
- package/src/utils/translateDiscovery.js +96 -0
- package/src/utils/translateNormalize.js +33 -0
- package/src/utils/translatePending.js +92 -0
- package/src/utils/translateStorage.js +142 -0
- package/.github/agents/developer.agent.md +0 -30
- package/.github/agents/devops.agent.md +0 -30
- package/.github/agents/qa.agent.md +0 -30
- package/.github/agents/security.agent.md +0 -30
- package/.github/workflows/npmjs.yml +0 -35
|
@@ -18,15 +18,18 @@ import RuntimeInfoFooter from '@controleonline/ui-common/src/react/components/Ru
|
|
|
18
18
|
import { useStore } from '@store';
|
|
19
19
|
import { api } from '@controleonline/ui-common/src/api';
|
|
20
20
|
import {app_type} from '@appType';
|
|
21
|
-
import {
|
|
21
|
+
import {env as APP_ENV} from '@env';
|
|
22
22
|
import { isPublicRoute } from '../router/publicRoutes';
|
|
23
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
buildTranslationBootstrapKey,
|
|
25
|
+
isTranslationBootstrapReady,
|
|
26
|
+
resolveConfiguredLanguage,
|
|
27
|
+
} = require('../utils/runtimeLanguage');
|
|
24
28
|
import {
|
|
25
29
|
applyPaletteToRuntimeColors,
|
|
26
30
|
applyThemeCssVariables,
|
|
27
31
|
resolveThemePalette,
|
|
28
32
|
} from '@controleonline/../../src/styles/branding';
|
|
29
|
-
import { resolveAppDomain } from '@controleonline/ui-common/src/utils/appDomain';
|
|
30
33
|
import { colors as runtimeColors } from '@controleonline/../../src/styles/colors';
|
|
31
34
|
import {
|
|
32
35
|
buildProviderManagedDeviceConfigs,
|
|
@@ -46,6 +49,9 @@ import {
|
|
|
46
49
|
import {
|
|
47
50
|
normalizeRuntimeMenuResponse,
|
|
48
51
|
} from '@controleonline/ui-common/src/react/utils/runtimeMenu';
|
|
52
|
+
import {
|
|
53
|
+
buildRuntimeZoomStyle,
|
|
54
|
+
} from '@controleonline/ui-common/src/react/utils/runtimeZoom';
|
|
49
55
|
import stores from '@stores';
|
|
50
56
|
import packageJson from '@package';
|
|
51
57
|
import providerStyles from './DefaultProvider.styles';
|
|
@@ -143,8 +149,12 @@ const selectRuntimeDeviceConfig = ({
|
|
|
143
149
|
})
|
|
144
150
|
.sort((left, right) => Number(right?.id || 0) - Number(left?.id || 0))[0] || null;
|
|
145
151
|
};
|
|
146
|
-
|
|
147
|
-
export const DefaultProvider = ({
|
|
152
|
+
|
|
153
|
+
export const DefaultProvider = ({
|
|
154
|
+
children,
|
|
155
|
+
currentRouteName = '',
|
|
156
|
+
onBootstrapReady,
|
|
157
|
+
}) => {
|
|
148
158
|
const appType = String(app_type || '').toUpperCase();
|
|
149
159
|
const isShopClientApp = appType === 'SHOP';
|
|
150
160
|
const themeStore = useStore('theme');
|
|
@@ -186,17 +196,20 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
186
196
|
const hasCurrentCompany =
|
|
187
197
|
!!currentCompany && Object.entries(currentCompany).length > 0;
|
|
188
198
|
|
|
189
|
-
const [translateReady, setTranslateReady] = useState(
|
|
199
|
+
const [translateReady, setTranslateReady] = useState(false);
|
|
200
|
+
const [activeTranslateBootstrapKey, setActiveTranslateBootstrapKey] =
|
|
201
|
+
useState('');
|
|
190
202
|
const [deviceConfigFetched, setDeviceConfigFetched] = useState(false);
|
|
191
203
|
const [mainConfigsDiscovered, setMainConfigsDiscovered] = useState(false);
|
|
192
204
|
const [deviceRuntimeConfigSynced, setDeviceRuntimeConfigSynced] =
|
|
193
205
|
useState(false);
|
|
194
|
-
const [currentRouteName, setCurrentRouteName] = useState('');
|
|
195
206
|
const [, setTranslateVersion] = useState(0);
|
|
196
207
|
const [baseThemeColors, setBaseThemeColors] = useState({});
|
|
197
208
|
const [bottomNavigationCount, setBottomNavigationCount] = useState(0);
|
|
198
209
|
const translateBootstrapKeyRef = useRef('');
|
|
199
210
|
const lastDeviceConfigPeopleIriRef = useRef('');
|
|
211
|
+
const walletPaymentTypeRequestRef = useRef({key: '', promise: null});
|
|
212
|
+
const walletPaymentTypeLoadedKeyRef = useRef('');
|
|
200
213
|
const [device, setDevice] = useState(
|
|
201
214
|
JSON.parse(localStorage.getItem('device') || '{}'),
|
|
202
215
|
);
|
|
@@ -211,12 +224,48 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
211
224
|
appType: app_type,
|
|
212
225
|
deviceInfo: device || {},
|
|
213
226
|
});
|
|
227
|
+
const runtimeUiScaleStyle = useMemo(
|
|
228
|
+
() => buildRuntimeZoomStyle(APP_ENV?.ZOOM, {isWeb: true}),
|
|
229
|
+
[],
|
|
230
|
+
);
|
|
214
231
|
const deviceConfigPeopleIri = resolveDeviceConfigPeopleIri({
|
|
215
232
|
appType,
|
|
216
233
|
currentCompany,
|
|
217
234
|
user,
|
|
218
235
|
});
|
|
219
236
|
const isPublicRouteActive = isPublicRoute(currentRouteName);
|
|
237
|
+
const currentTranslationConfig = JSON.parse(
|
|
238
|
+
localStorage.getItem('config') || '{}',
|
|
239
|
+
);
|
|
240
|
+
const currentTranslationSession = JSON.parse(
|
|
241
|
+
localStorage.getItem('session') || '{}',
|
|
242
|
+
);
|
|
243
|
+
const configuredTranslationLanguage = resolveConfiguredLanguage({
|
|
244
|
+
currentCompany,
|
|
245
|
+
defaultCompany,
|
|
246
|
+
currentConfig: currentTranslationConfig,
|
|
247
|
+
sessionData: currentTranslationSession,
|
|
248
|
+
});
|
|
249
|
+
const expectedTranslateBootstrapKey = isLogged && hasCurrentCompany
|
|
250
|
+
? buildTranslationBootstrapKey({
|
|
251
|
+
language: configuredTranslationLanguage,
|
|
252
|
+
currentCompanyId: normalizeEntityId(currentCompany?.id),
|
|
253
|
+
defaultCompanyId: normalizeEntityId(defaultCompany?.id),
|
|
254
|
+
})
|
|
255
|
+
: '';
|
|
256
|
+
const requiresTranslateBootstrap = Boolean(
|
|
257
|
+
isLogged &&
|
|
258
|
+
hasCurrentCompany &&
|
|
259
|
+
currentRouteName &&
|
|
260
|
+
!isPublicRouteActive,
|
|
261
|
+
);
|
|
262
|
+
const isTranslateBootstrapReady = isTranslationBootstrapReady({
|
|
263
|
+
activeKey: activeTranslateBootstrapKey,
|
|
264
|
+
expectedKey: expectedTranslateBootstrapKey,
|
|
265
|
+
required: requiresTranslateBootstrap,
|
|
266
|
+
ready: translateReady,
|
|
267
|
+
translator: global.t,
|
|
268
|
+
});
|
|
220
269
|
|
|
221
270
|
const registerBottomNavigation = useCallback(() => {
|
|
222
271
|
setBottomNavigationCount(current => current + 1);
|
|
@@ -274,30 +323,13 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
274
323
|
};
|
|
275
324
|
}, []);
|
|
276
325
|
|
|
277
|
-
useEffect(() => {
|
|
278
|
-
global.setRuntimeRouteName = routeName => {
|
|
279
|
-
const normalizedRouteName = String(routeName || '').trim();
|
|
280
|
-
|
|
281
|
-
setCurrentRouteName(previousRouteName =>
|
|
282
|
-
previousRouteName === normalizedRouteName
|
|
283
|
-
? previousRouteName
|
|
284
|
-
: normalizedRouteName,
|
|
285
|
-
);
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
return () => {
|
|
289
|
-
if (global.setRuntimeRouteName) {
|
|
290
|
-
delete global.setRuntimeRouteName;
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
}, []);
|
|
294
|
-
|
|
295
326
|
useEffect(() => {
|
|
296
327
|
if (isLogged && !isPublicRouteActive) {
|
|
297
328
|
return;
|
|
298
329
|
}
|
|
299
330
|
|
|
300
331
|
setTranslateReady(true);
|
|
332
|
+
setActiveTranslateBootstrapKey('');
|
|
301
333
|
translateBootstrapKeyRef.current = '';
|
|
302
334
|
translateActions.setMessages({});
|
|
303
335
|
translateActions.setPendingMessages?.({});
|
|
@@ -305,7 +337,7 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
305
337
|
if (global.t) {
|
|
306
338
|
delete global.t;
|
|
307
339
|
}
|
|
308
|
-
}, [isLogged, isPublicRouteActive]);
|
|
340
|
+
}, [isLogged, isPublicRouteActive, translateActions]);
|
|
309
341
|
|
|
310
342
|
useEffect(() => {
|
|
311
343
|
if (
|
|
@@ -526,18 +558,45 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
526
558
|
: device_config?.configs;
|
|
527
559
|
|
|
528
560
|
if (!currentCompany?.id || !paymentConfigSource) {
|
|
561
|
+
walletPaymentTypeRequestRef.current = {key: '', promise: null};
|
|
562
|
+
walletPaymentTypeLoadedKeyRef.current = '';
|
|
529
563
|
paymentTypeActions.setItems([]);
|
|
530
564
|
return;
|
|
531
565
|
}
|
|
532
566
|
|
|
567
|
+
const paymentTypeSignature = resolveDevicePaymentTypeIds(paymentConfigSource)
|
|
568
|
+
.sort()
|
|
569
|
+
.join(',');
|
|
570
|
+
const requestKey = `${currentCompany.id}:${paymentTypeSignature}`;
|
|
571
|
+
|
|
572
|
+
if (walletPaymentTypeLoadedKeyRef.current === requestKey) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const existingRequestPromise =
|
|
577
|
+
walletPaymentTypeRequestRef.current.key === requestKey &&
|
|
578
|
+
walletPaymentTypeRequestRef.current.promise
|
|
579
|
+
? walletPaymentTypeRequestRef.current.promise
|
|
580
|
+
: null;
|
|
581
|
+
|
|
533
582
|
let isMounted = true;
|
|
534
583
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
584
|
+
const requestPromise =
|
|
585
|
+
existingRequestPromise ||
|
|
586
|
+
api.fetch('wallet_payment_types', {
|
|
587
|
+
params: {
|
|
588
|
+
people: `/people/${currentCompany.id}`,
|
|
589
|
+
},
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
if (!existingRequestPromise) {
|
|
593
|
+
walletPaymentTypeRequestRef.current = {
|
|
594
|
+
key: requestKey,
|
|
595
|
+
promise: requestPromise,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
requestPromise
|
|
541
600
|
.then(response => {
|
|
542
601
|
if (!isMounted) {
|
|
543
602
|
return;
|
|
@@ -561,11 +620,20 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
561
620
|
allowedPaymentTypeIds,
|
|
562
621
|
),
|
|
563
622
|
);
|
|
623
|
+
walletPaymentTypeLoadedKeyRef.current = requestKey;
|
|
564
624
|
})
|
|
565
625
|
.catch(() => {
|
|
566
626
|
if (isMounted) {
|
|
567
627
|
paymentTypeActions.setItems([]);
|
|
568
628
|
}
|
|
629
|
+
})
|
|
630
|
+
.finally(() => {
|
|
631
|
+
if (
|
|
632
|
+
walletPaymentTypeRequestRef.current.key === requestKey &&
|
|
633
|
+
walletPaymentTypeRequestRef.current.promise === requestPromise
|
|
634
|
+
) {
|
|
635
|
+
walletPaymentTypeRequestRef.current = {key: '', promise: null};
|
|
636
|
+
}
|
|
569
637
|
});
|
|
570
638
|
|
|
571
639
|
return () => {
|
|
@@ -713,56 +781,48 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
713
781
|
}, [currentCompany, isLogged, mainConfigsDiscovered]);
|
|
714
782
|
|
|
715
783
|
useEffect(() => {
|
|
716
|
-
if (
|
|
717
|
-
!currentRouteName ||
|
|
718
|
-
isPublicRouteActive
|
|
719
|
-
) {
|
|
784
|
+
if (!currentRouteName || isPublicRouteActive) {
|
|
720
785
|
return;
|
|
721
786
|
}
|
|
722
787
|
|
|
723
788
|
if (
|
|
724
789
|
!isLogged ||
|
|
725
|
-
|
|
726
|
-
!deviceConfigFetched
|
|
790
|
+
!hasCurrentCompany ||
|
|
791
|
+
!deviceConfigFetched ||
|
|
792
|
+
!expectedTranslateBootstrapKey
|
|
727
793
|
) {
|
|
728
794
|
return;
|
|
729
795
|
}
|
|
730
796
|
|
|
731
797
|
const currentConfig = JSON.parse(localStorage.getItem('config') || '{}');
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
configuredLanguage,
|
|
743
|
-
currentCompanyId,
|
|
744
|
-
defaultCompanyId,
|
|
745
|
-
].join('::');
|
|
746
|
-
|
|
747
|
-
if (translateBootstrapKeyRef.current === nextTranslateBootstrapKey) {
|
|
748
|
-
if (global.t) {
|
|
749
|
-
global.t.companies = companies;
|
|
750
|
-
global.t.currentCompany = currentCompany;
|
|
751
|
-
global.t.defaultCompany = defaultCompany;
|
|
752
|
-
}
|
|
798
|
+
|
|
799
|
+
if (
|
|
800
|
+
translateBootstrapKeyRef.current === expectedTranslateBootstrapKey &&
|
|
801
|
+
global.t
|
|
802
|
+
) {
|
|
803
|
+
global.t.companies = companies;
|
|
804
|
+
global.t.currentCompany = currentCompany;
|
|
805
|
+
global.t.defaultCompany = defaultCompany;
|
|
806
|
+
setActiveTranslateBootstrapKey(expectedTranslateBootstrapKey);
|
|
807
|
+
setTranslateReady(true);
|
|
753
808
|
|
|
754
809
|
return;
|
|
755
810
|
}
|
|
756
811
|
|
|
757
|
-
|
|
758
|
-
|
|
812
|
+
setTranslateReady(false);
|
|
813
|
+
|
|
814
|
+
if (currentConfig.language !== configuredTranslationLanguage) {
|
|
815
|
+
const nextConfig = {
|
|
816
|
+
...currentConfig,
|
|
817
|
+
language: configuredTranslationLanguage,
|
|
818
|
+
};
|
|
759
819
|
localStorage.setItem(
|
|
760
820
|
'config',
|
|
761
821
|
JSON.stringify(nextConfig),
|
|
762
822
|
);
|
|
763
823
|
}
|
|
764
824
|
|
|
765
|
-
translateBootstrapKeyRef.current =
|
|
825
|
+
translateBootstrapKeyRef.current = expectedTranslateBootstrapKey;
|
|
766
826
|
global.t = new Translate(
|
|
767
827
|
companies,
|
|
768
828
|
defaultCompany,
|
|
@@ -770,24 +830,38 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
770
830
|
Object.keys(stores),
|
|
771
831
|
translateStore,
|
|
772
832
|
);
|
|
833
|
+
setActiveTranslateBootstrapKey(expectedTranslateBootstrapKey);
|
|
773
834
|
setTranslateReady(true);
|
|
774
835
|
global.refreshTranslationsUI?.();
|
|
775
836
|
}, [
|
|
776
837
|
companies,
|
|
838
|
+
configuredTranslationLanguage,
|
|
777
839
|
currentCompany,
|
|
778
840
|
currentRouteName,
|
|
779
841
|
defaultCompany,
|
|
780
842
|
deviceConfigFetched,
|
|
843
|
+
expectedTranslateBootstrapKey,
|
|
844
|
+
hasCurrentCompany,
|
|
781
845
|
isLogged,
|
|
782
846
|
isPublicRouteActive,
|
|
783
|
-
|
|
847
|
+
translateStore,
|
|
848
|
+
]);
|
|
849
|
+
|
|
850
|
+
useEffect(() => {
|
|
851
|
+
if (
|
|
852
|
+
!isLogged ||
|
|
853
|
+
!hasCurrentCompany ||
|
|
854
|
+
(currentRouteName && isTranslateBootstrapReady)
|
|
855
|
+
) {
|
|
856
|
+
onBootstrapReady?.();
|
|
857
|
+
}
|
|
858
|
+
}, [
|
|
859
|
+
currentRouteName,
|
|
860
|
+
hasCurrentCompany,
|
|
861
|
+
isLogged,
|
|
862
|
+
isTranslateBootstrapReady,
|
|
863
|
+
onBootstrapReady,
|
|
784
864
|
]);
|
|
785
|
-
|
|
786
|
-
useEffect(() => {
|
|
787
|
-
if (!isLogged || translateReady || !hasCurrentCompany) {
|
|
788
|
-
onBootstrapReady?.();
|
|
789
|
-
}
|
|
790
|
-
}, [isLogged, translateReady, hasCurrentCompany, onBootstrapReady]);
|
|
791
865
|
|
|
792
866
|
useEffect(() => {
|
|
793
867
|
if (device && device.id && isLogged) {
|
|
@@ -829,13 +903,9 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
829
903
|
|
|
830
904
|
useEffect(() => {
|
|
831
905
|
const fetchColors = async () => {
|
|
832
|
-
const appDomain = resolveAppDomain(APP_ENV.DOMAIN);
|
|
833
|
-
const params = appDomain ? { 'app-domain': appDomain } : undefined;
|
|
834
|
-
|
|
835
906
|
try {
|
|
836
907
|
const cssText = await api.fetch('themes-colors.css', {
|
|
837
908
|
responseType: 'text',
|
|
838
|
-
params,
|
|
839
909
|
});
|
|
840
910
|
const parsedColors = parseThemeCss(cssText);
|
|
841
911
|
setBaseThemeColors(parsedColors);
|
|
@@ -875,6 +945,10 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
875
945
|
isShopClientApp,
|
|
876
946
|
]);
|
|
877
947
|
|
|
948
|
+
if (requiresTranslateBootstrap && !isTranslateBootstrapReady) {
|
|
949
|
+
return <View style={providerStyles.loadingContainer} />;
|
|
950
|
+
}
|
|
951
|
+
|
|
878
952
|
return (
|
|
879
953
|
<ThemeContext.Provider value={themeContextValue}>
|
|
880
954
|
<View
|
|
@@ -884,7 +958,7 @@ export const DefaultProvider = ({ children, onBootstrapReady }) => {
|
|
|
884
958
|
backgroundColor: colors?.background || runtimeColors.background,
|
|
885
959
|
},
|
|
886
960
|
]}>
|
|
887
|
-
<View style={providerStyles.content}>{children}</View>
|
|
961
|
+
<View style={[providerStyles.content, runtimeUiScaleStyle]}>{children}</View>
|
|
888
962
|
{!isShopClientApp && bottomNavigationCount === 0 && (
|
|
889
963
|
<RuntimeInfoFooter
|
|
890
964
|
appVersion={appVersion}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import React, {useMemo} from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
Modal,
|
|
5
|
+
ScrollView,
|
|
6
|
+
Text,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
View,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import Icon from 'react-native-vector-icons/Feather';
|
|
11
|
+
|
|
12
|
+
import styles from './NetworkPrinterPreviewModal.styles';
|
|
13
|
+
|
|
14
|
+
const tt = key => global.t?.t('configs', 'printPreview', key);
|
|
15
|
+
|
|
16
|
+
const clampColumns = value => {
|
|
17
|
+
const parsedValue = Number(String(value || '').replace(/\D+/g, ''));
|
|
18
|
+
if (!Number.isFinite(parsedValue) || parsedValue <= 0) {
|
|
19
|
+
return 48;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return Math.min(Math.max(parsedValue, 24), 80);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const safeText = value => String(value || '').trim();
|
|
26
|
+
|
|
27
|
+
const normalizePreviewLine = line => {
|
|
28
|
+
if (line && typeof line === 'object') {
|
|
29
|
+
return {
|
|
30
|
+
...line,
|
|
31
|
+
text: safeText(line.text),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
text: safeText(line),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const centerLine = (value, columns) => {
|
|
41
|
+
const text = safeText(value);
|
|
42
|
+
if (text.length >= columns) {
|
|
43
|
+
return text.slice(0, columns);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const leftPad = Math.floor((columns - text.length) / 2);
|
|
47
|
+
return `${' '.repeat(leftPad)}${text}`;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const wrapLine = (value, columns) => {
|
|
51
|
+
const words = safeText(value).split(/\s+/).filter(Boolean);
|
|
52
|
+
const lines = [];
|
|
53
|
+
let currentLine = '';
|
|
54
|
+
|
|
55
|
+
words.forEach(word => {
|
|
56
|
+
if (!currentLine) {
|
|
57
|
+
currentLine = word;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (`${currentLine} ${word}`.length <= columns) {
|
|
62
|
+
currentLine = `${currentLine} ${word}`;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
lines.push(currentLine);
|
|
67
|
+
currentLine = word;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (currentLine) {
|
|
71
|
+
lines.push(currentLine);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return lines.length > 0 ? lines : [''];
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const wrapPreviewLine = (line, columns) => {
|
|
78
|
+
const normalizedLine = normalizePreviewLine(line);
|
|
79
|
+
return wrapLine(normalizedLine.text, columns).map(text => ({
|
|
80
|
+
...normalizedLine,
|
|
81
|
+
text,
|
|
82
|
+
}));
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const NetworkPrinterPreviewModal = ({
|
|
86
|
+
visible = false,
|
|
87
|
+
onClose,
|
|
88
|
+
codePage = '',
|
|
89
|
+
columns,
|
|
90
|
+
documents = [],
|
|
91
|
+
error = '',
|
|
92
|
+
logoUrl = '',
|
|
93
|
+
loading = false,
|
|
94
|
+
printerModel,
|
|
95
|
+
printerManufacturer,
|
|
96
|
+
subtitle = '',
|
|
97
|
+
title = '',
|
|
98
|
+
transport,
|
|
99
|
+
}) => {
|
|
100
|
+
const normalizedColumns = useMemo(() => clampColumns(columns), [columns]);
|
|
101
|
+
const normalizedDocuments = useMemo(
|
|
102
|
+
() => (Array.isArray(documents) ? documents : []),
|
|
103
|
+
[documents],
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<Modal
|
|
108
|
+
visible={visible}
|
|
109
|
+
transparent
|
|
110
|
+
animationType="fade"
|
|
111
|
+
onRequestClose={onClose}>
|
|
112
|
+
<View style={styles.backdrop}>
|
|
113
|
+
<View style={styles.panel}>
|
|
114
|
+
<View style={styles.header}>
|
|
115
|
+
<View style={styles.headerCopy}>
|
|
116
|
+
<Text style={styles.title}>{title || tt('title') || 'Visualizacao da impressao'}</Text>
|
|
117
|
+
<Text style={styles.subtitle}>
|
|
118
|
+
{subtitle ||
|
|
119
|
+
tt('subtitle') ||
|
|
120
|
+
'Simulacao local para conferir largura, quebras e campos do cupom.'}
|
|
121
|
+
</Text>
|
|
122
|
+
</View>
|
|
123
|
+
<TouchableOpacity
|
|
124
|
+
style={styles.closeButton}
|
|
125
|
+
activeOpacity={0.85}
|
|
126
|
+
onPress={onClose}>
|
|
127
|
+
<Icon name="x" size={18} color="#0F172A" />
|
|
128
|
+
</TouchableOpacity>
|
|
129
|
+
</View>
|
|
130
|
+
|
|
131
|
+
<ScrollView contentContainerStyle={styles.content}>
|
|
132
|
+
<View style={styles.metaGrid}>
|
|
133
|
+
<View style={styles.metaChip}>
|
|
134
|
+
<Text style={styles.metaText}>
|
|
135
|
+
{`${normalizedColumns} ${tt('columns') || 'colunas'}`}
|
|
136
|
+
</Text>
|
|
137
|
+
</View>
|
|
138
|
+
<View style={styles.metaChip}>
|
|
139
|
+
<Text style={styles.metaText}>
|
|
140
|
+
{`${tt('codePage') || 'Code page'}: ${safeText(codePage) || 'cp850'}`}
|
|
141
|
+
</Text>
|
|
142
|
+
</View>
|
|
143
|
+
<View style={styles.metaChip}>
|
|
144
|
+
<Text style={styles.metaText}>
|
|
145
|
+
{safeText(transport) || tt('transportFallback') || 'tcp-raw'}
|
|
146
|
+
</Text>
|
|
147
|
+
</View>
|
|
148
|
+
<View style={styles.metaChip}>
|
|
149
|
+
<Text style={styles.metaText}>
|
|
150
|
+
{[printerManufacturer, printerModel]
|
|
151
|
+
.map(safeText)
|
|
152
|
+
.filter(Boolean)
|
|
153
|
+
.join(' ') || tt('modelMissing') || 'Modelo nao informado'}
|
|
154
|
+
</Text>
|
|
155
|
+
</View>
|
|
156
|
+
</View>
|
|
157
|
+
|
|
158
|
+
{loading ? (
|
|
159
|
+
<View style={styles.stateBox}>
|
|
160
|
+
<Text style={styles.stateText}>{tt('loadingRealData') || 'Carregando dados reais...'}</Text>
|
|
161
|
+
</View>
|
|
162
|
+
) : error ? (
|
|
163
|
+
<View style={styles.errorBox}>
|
|
164
|
+
<Text style={styles.errorText}>{error}</Text>
|
|
165
|
+
</View>
|
|
166
|
+
) : normalizedDocuments.length > 0 ? (
|
|
167
|
+
normalizedDocuments.map((document, index) => {
|
|
168
|
+
const lines = Array.isArray(document?.lines)
|
|
169
|
+
? document.lines
|
|
170
|
+
: [];
|
|
171
|
+
const defaultHeaderLines = document?.hideDefaultHeader
|
|
172
|
+
? []
|
|
173
|
+
: [
|
|
174
|
+
{
|
|
175
|
+
text: centerLine(
|
|
176
|
+
document?.title || `${tt('copy') || 'Via'} ${index + 1}`,
|
|
177
|
+
normalizedColumns,
|
|
178
|
+
),
|
|
179
|
+
},
|
|
180
|
+
document?.subtitle
|
|
181
|
+
? {text: centerLine(document.subtitle, normalizedColumns)}
|
|
182
|
+
: null,
|
|
183
|
+
{text: '-'.repeat(normalizedColumns)},
|
|
184
|
+
].filter(Boolean);
|
|
185
|
+
const paperLines = [
|
|
186
|
+
...defaultHeaderLines,
|
|
187
|
+
...lines.flatMap(line => wrapPreviewLine(line, normalizedColumns)),
|
|
188
|
+
].filter(Boolean);
|
|
189
|
+
const receiptWidth = normalizedColumns * 8;
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<View key={`${document?.title || 'preview'}-${index}`}>
|
|
193
|
+
{index > 0 ? (
|
|
194
|
+
<View style={styles.cutLine}>
|
|
195
|
+
<Text style={styles.cutText}>{tt('cutLine') || 'picote'}</Text>
|
|
196
|
+
</View>
|
|
197
|
+
) : null}
|
|
198
|
+
<View style={styles.paper}>
|
|
199
|
+
<View style={[styles.receiptWrap, {width: receiptWidth}]}>
|
|
200
|
+
{logoUrl && !document?.hideLogo ? (
|
|
201
|
+
<View style={styles.logoWrap}>
|
|
202
|
+
<Image
|
|
203
|
+
source={{uri: logoUrl}}
|
|
204
|
+
style={styles.logo}
|
|
205
|
+
resizeMode="contain"
|
|
206
|
+
/>
|
|
207
|
+
</View>
|
|
208
|
+
) : null}
|
|
209
|
+
{paperLines.map((line, lineIndex) => (
|
|
210
|
+
<Text
|
|
211
|
+
key={`${document?.title || 'preview'}-${index}-${lineIndex}`}
|
|
212
|
+
style={[
|
|
213
|
+
styles.receiptText,
|
|
214
|
+
line.center ? styles.receiptTextCenter : null,
|
|
215
|
+
line.bold ? styles.receiptTextBold : null,
|
|
216
|
+
line.reverse ? styles.receiptTextReverse : null,
|
|
217
|
+
line.reverse && line.center
|
|
218
|
+
? styles.receiptTextReverseCenter
|
|
219
|
+
: null,
|
|
220
|
+
line.large ? styles.receiptTextLarge : null,
|
|
221
|
+
]}>
|
|
222
|
+
{line.text || ' '}
|
|
223
|
+
</Text>
|
|
224
|
+
))}
|
|
225
|
+
</View>
|
|
226
|
+
</View>
|
|
227
|
+
</View>
|
|
228
|
+
);
|
|
229
|
+
})
|
|
230
|
+
) : (
|
|
231
|
+
<View style={styles.stateBox}>
|
|
232
|
+
<Text style={styles.stateText}>
|
|
233
|
+
{tt('emptyData') || 'Nenhum dado real encontrado para visualizar.'}
|
|
234
|
+
</Text>
|
|
235
|
+
</View>
|
|
236
|
+
)}
|
|
237
|
+
|
|
238
|
+
<Text style={styles.hint}>
|
|
239
|
+
{tt('hint') ||
|
|
240
|
+
'Esta visualizacao ainda nao envia dados para a impressora. Os blocos separados simulam os cortes de papel usados pelas filas.'}
|
|
241
|
+
</Text>
|
|
242
|
+
</ScrollView>
|
|
243
|
+
</View>
|
|
244
|
+
</View>
|
|
245
|
+
</Modal>
|
|
246
|
+
);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export default NetworkPrinterPreviewModal;
|