@controleonline/ui-common 1.2.70 → 1.2.71

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 (61) hide show
  1. package/package.json +31 -28
  2. package/src/api/index.js +237 -37
  3. package/src/react/components/AddImportModal.js +1 -1
  4. package/src/react/components/AnimatedModal.js +171 -0
  5. package/src/react/components/AnimatedModal.styles.js +21 -0
  6. package/src/react/components/AppTypeSwitcher.js +164 -0
  7. package/src/react/components/AppTypeSwitcher.styles.js +109 -0
  8. package/src/react/components/BackgroundRuntimeBridge.js +5 -4
  9. package/src/react/components/BottomNavigationBar.js +86 -31
  10. package/src/react/components/BottomNavigationBar.styles.js +118 -110
  11. package/src/react/components/DefaultProvider.native.js +68 -66
  12. package/src/react/components/DefaultProvider.web.js +44 -42
  13. package/src/react/components/DeliveryPushBridge.native.js +2 -2
  14. package/src/react/components/DeviceAlertSoundService.js +3 -3
  15. package/src/react/components/KioskModeBridge.js +2 -2
  16. package/src/react/components/LauncherModeBridge.js +2 -2
  17. package/src/react/components/ManagerPushBridge.native.js +2 -2
  18. package/src/react/components/RemoteCheckoutService.js +28 -20
  19. package/src/react/components/RuntimeBottomNavigationBar.js +146 -119
  20. package/src/react/components/RuntimeInfoFooter.js +37 -9
  21. package/src/react/components/StateStore.js +258 -0
  22. package/src/react/components/WebsocketListener.native.js +11 -11
  23. package/src/react/config/deviceConfigBootstrap.js +66 -27
  24. package/src/react/css/orders.js +72 -0
  25. package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +484 -454
  26. package/src/react/pages/SettingsPage/index.js +1266 -1167
  27. package/src/react/print/providers/local.js +1 -1
  28. package/src/react/router/publicRoutes.js +25 -0
  29. package/src/react/services/Cielo/Checkout.js +39 -0
  30. package/src/react/services/Cielo/Cielo.js +193 -0
  31. package/src/react/services/Cielo/Print.js +7 -0
  32. package/src/react/services/InfinitePay/Checkout.js +33 -0
  33. package/src/react/services/InfinitePay/InfinitePay.js +24 -0
  34. package/src/react/{utils → services}/paymentGatewayExecution.js +91 -91
  35. package/src/react/styles/global.js +115 -0
  36. package/src/react/utils/fileUrl.js +182 -16
  37. package/src/react/utils/menuNavigation.js +31 -0
  38. package/src/react/utils/orderIdentity.js +277 -0
  39. package/src/react/utils/remotePayment.js +115 -61
  40. package/src/react/utils/runtimeMenu.js +35 -3
  41. package/src/react/utils/shopConfig.js +50 -24
  42. package/src/react/utils/shopFranchises.js +56 -22
  43. package/src/react/utils/socketRuntimePipeline.js +14 -14
  44. package/src/store/configs/index.js +2 -2
  45. package/src/tests/react/api/loadSmokeIndex.test.js +75 -0
  46. package/src/tests/react/config/deviceConfigBootstrap.test.js +47 -0
  47. package/src/tests/react/print/localPrintProvider.test.js +1 -1
  48. package/src/tests/react/services/Cielo.test.js +190 -0
  49. package/src/tests/react/utils/fileUrl.test.js +62 -0
  50. package/src/tests/react/utils/importStatus.test.js +2 -2
  51. package/src/tests/react/utils/orderIdentity.test.js +139 -0
  52. package/src/tests/react/utils/remotePayment.test.js +62 -0
  53. package/src/tests/react/utils/runtimeFooter.test.js +4 -6
  54. package/src/tests/react/utils/runtimeLanguage.test.js +2 -2
  55. package/src/tests/react/utils/runtimeMenu.test.js +23 -3
  56. package/src/tests/react/utils/shopConfig.test.js +74 -0
  57. package/src/tests/react/utils/shopFranchises.test.js +79 -12
  58. package/src/tests/react/utils/translate.test.mjs +166 -102
  59. package/src/utils/formatter.js +18 -0
  60. package/src/utils/integrationConfigs.js +80 -79
  61. package/src/utils/translate.js +125 -30
@@ -1,7 +1,7 @@
1
1
  import React, {useCallback, useEffect, useMemo, useRef} from 'react';
2
2
  import {Platform} from 'react-native';
3
3
  import * as Notifications from 'expo-notifications';
4
- import {env as APP_ENV} from '@env';
4
+ import {app_type} from '@appType';
5
5
  import {useStore} from '@store';
6
6
  import {
7
7
  ensureManagerOrderNotificationPermission,
@@ -93,7 +93,7 @@ const ManagerPushBridge = ({device, setDevice}) => {
93
93
  const deviceActions = deviceStore.actions;
94
94
 
95
95
  const {isLogged, sessionChecked, user} = authGetters;
96
- const isManagerRuntime = isManagerAppType(APP_ENV?.APP_TYPE);
96
+ const isManagerRuntime = isManagerAppType(app_type);
97
97
  const pushPreferences = useMemo(
98
98
  () => resolveManagerOrderNotificationPreferences(user),
99
99
  [user],
@@ -2,17 +2,18 @@ import React, {useEffect, useCallback, useRef} from 'react';
2
2
 
3
3
  import {api} from '@controleonline/ui-common/src/api';
4
4
  import Formatter from '@controleonline/ui-common/src/utils/formatter';
5
+ import {
6
+ createInvoiceForGatewayFreePayment,
7
+ isGatewayFreePayment,
8
+ } from '@controleonline/ui-common/src/react/utils/cashPayment';
9
+ import {
10
+ normalizeGatewayPaymentError,
11
+ runConfiguredGatewayPayment,
12
+ } from '../services/paymentGatewayExecution';
5
13
  import {
6
- createInvoiceForGatewayFreePayment,
7
- isGatewayFreePayment,
8
- } from '@controleonline/ui-common/src/react/utils/cashPayment';
9
- import {
10
- normalizeGatewayPaymentError,
11
- runConfiguredGatewayPayment,
12
- } from '@controleonline/ui-common/src/react/utils/paymentGatewayExecution';
13
- import {
14
- buildRemotePaymentResultMessage,
15
- isRemotePaymentRequestMessage,
14
+ buildRemotePaymentResultMessage,
15
+ isRemotePaymentCancellation,
16
+ isRemotePaymentRequestMessage,
16
17
  normalizeRemotePaymentRequestKey,
17
18
  } from '@controleonline/ui-common/src/react/utils/remotePayment';
18
19
 
@@ -255,16 +256,23 @@ const Checkout = () => {
255
256
  paidAmount,
256
257
  status: 'success',
257
258
  });
258
- } catch (error) {
259
- const errorMessage = normalizeGatewayPaymentError(
260
- error,
261
- 'Nao foi possivel concluir o pagamento remoto.',
262
- );
263
- invoiceActions.setError(errorMessage);
264
- await sendRemoteResult({
265
- error: errorMessage,
266
- status: 'error',
267
- });
259
+ } catch (error) {
260
+ const errorMessage = normalizeGatewayPaymentError(
261
+ error,
262
+ 'Nao foi possivel concluir o pagamento remoto.',
263
+ );
264
+ const wasCanceled = isRemotePaymentCancellation({
265
+ status: error?.status,
266
+ error: errorMessage,
267
+ });
268
+
269
+ if (!wasCanceled) {
270
+ invoiceActions.setError(errorMessage);
271
+ }
272
+ await sendRemoteResult({
273
+ error: errorMessage,
274
+ status: wasCanceled ? 'canceled' : 'error',
275
+ });
268
276
  } finally {
269
277
  clear();
270
278
  processingMessageKeyRef.current = '';
@@ -1,28 +1,27 @@
1
- import React, {useEffect, useMemo, useState} from 'react';
2
- import {useNavigationState} from '@react-navigation/native';
3
- import {useStore} from '@store';
4
- import {api} from '@controleonline/ui-common/src/api';
5
- import {env as APP_ENV} from '@env';
6
- import {colors as runtimeColors} from '@controleonline/../../src/styles/colors';
7
- import {resolveThemePalette} from '@controleonline/../../src/styles/branding';
8
- import BottomNavigationBar from '@controleonline/ui-common/src/react/components/BottomNavigationBar';
1
+ import React, {useEffect, useMemo, useState} from 'react';
2
+ import {useNavigationState} from '@react-navigation/native';
3
+ import {useStore} from '@store';
4
+ import {api} from '@controleonline/ui-common/src/api';
5
+ import {app_type} from '@appType';
6
+ import BottomNavigationBar from '@controleonline/ui-common/src/react/components/BottomNavigationBar';
9
7
  import {
10
8
  getBottomNavigationPreset,
9
+ resolveBottomNavigationItems,
11
10
  resolveBottomNavigationRoute,
12
11
  } from '@controleonline/ui-common/src/react/components/BottomNavigationBar.config';
13
- import {
14
- filterRuntimeMenuModulesByType,
15
- normalizeAppType,
16
- normalizeRuntimeMenuResponse,
17
- resolveRuntimeMenuLabel,
18
- } from '@controleonline/ui-common/src/react/utils/runtimeMenu';
19
-
20
- const sortRuntimeMenuItems = (left, right) => {
21
- const orderDiff = Number(left?.sortOrder || 0) - Number(right?.sortOrder || 0);
22
- if (orderDiff !== 0) return orderDiff;
23
- return String(left?.label || '').localeCompare(String(right?.label || ''));
24
- };
25
-
12
+ import {
13
+ filterRuntimeMenuModulesByType,
14
+ normalizeAppType,
15
+ normalizeRuntimeMenuResponse,
16
+ resolveRuntimeMenuLabel,
17
+ } from '@controleonline/ui-common/src/react/utils/runtimeMenu';
18
+
19
+ const sortRuntimeMenuItems = (left, right) => {
20
+ const orderDiff = Number(left?.sortOrder || 0) - Number(right?.sortOrder || 0);
21
+ if (orderDiff !== 0) return orderDiff;
22
+ return String(left?.label || '').localeCompare(String(right?.label || ''));
23
+ };
24
+
26
25
  const RuntimeBottomNavigationBar = ({
27
26
  activeRouteName: activeRouteNameProp,
28
27
  colors: colorsOverride,
@@ -31,14 +30,15 @@ const RuntimeBottomNavigationBar = ({
31
30
  itemMapper,
32
31
  menuType = 'toolbar',
33
32
  navigation,
34
- presetKey,
35
- routeAliases: routeAliasesProp,
36
- testID = 'bottom-navigation',
37
- }) => {
38
- const state = useNavigationState(current => current);
39
- const activeRouteName =
40
- activeRouteNameProp || state?.routes?.[state.index]?.name || 'HomePage';
41
-
33
+ presetKey,
34
+ routeAliases: routeAliasesProp,
35
+ testID = 'bottom-navigation',
36
+ useModernWebChromeProps = false,
37
+ }) => {
38
+ const state = useNavigationState(current => current);
39
+ const activeRouteName =
40
+ activeRouteNameProp || state?.routes?.[state.index]?.name || 'HomePage';
41
+
42
42
  const themeStore = useStore('theme');
43
43
  const peopleStore = useStore('people');
44
44
  const themeGetters = themeStore?.getters || {};
@@ -48,7 +48,7 @@ const RuntimeBottomNavigationBar = ({
48
48
  const [runtimeMenus, setRuntimeMenus] = useState([]);
49
49
  const preset = presetKey ? getBottomNavigationPreset(presetKey) : null;
50
50
  const routeAliases = routeAliasesProp || preset?.routeAliases || {};
51
- const appType = normalizeAppType(APP_ENV.APP_TYPE);
51
+ const appType = normalizeAppType(app_type);
52
52
 
53
53
  useEffect(() => {
54
54
  if (!currentCompany?.id || !menuType) {
@@ -56,96 +56,123 @@ const RuntimeBottomNavigationBar = ({
56
56
  return undefined;
57
57
  }
58
58
 
59
- let cancelled = false;
60
- setRuntimeMenus([]);
59
+ if (preset) {
60
+ const presetMenus = Array.isArray(preset?.items)
61
+ ? resolveBottomNavigationItems(
62
+ preset.items.map((item, index) => ({
63
+ ...item,
64
+ menuType,
65
+ sortOrder: Number(item?.sortOrder || (index + 1) * 10),
66
+ })),
67
+ global.t?.t,
68
+ )
69
+ : [];
61
70
 
62
- api
63
- .fetch('menus-people', {
64
- params: {
65
- myCompany: currentCompany.id,
66
- appType,
67
- menuType,
71
+ setRuntimeMenus([
72
+ {
73
+ id: presetKey || 'runtime-bottom-navigation',
74
+ label: preset?.label || presetKey || '',
75
+ icon: preset?.icon || '',
76
+ menus: presetMenus,
68
77
  },
69
- })
70
- .then(result => {
71
- if (!cancelled) {
72
- setRuntimeMenus(
73
- normalizeRuntimeMenuResponse(result, {
74
- appType,
75
- allowFallback: false,
76
- }),
77
- );
78
- }
79
- })
80
- .catch(() => {
81
- if (!cancelled) {
82
- setRuntimeMenus([]);
83
- }
84
- });
85
-
86
- return () => {
87
- cancelled = true;
88
- };
89
- }, [appType, currentCompany?.id, menuType]);
90
-
91
- const colors = useMemo(() => {
92
- if (colorsOverride) {
93
- return colorsOverride;
78
+ ]);
79
+ return undefined;
94
80
  }
95
81
 
96
- return resolveThemePalette(
97
- {
98
- ...themeColors,
99
- ...(currentCompany?.theme?.colors || {}),
100
- },
101
- runtimeColors,
102
- );
103
- }, [colorsOverride, currentCompany?.theme?.colors, themeColors]);
104
-
105
- const navItems = useMemo(() => {
106
- const mapper = typeof itemMapper === 'function' ? itemMapper : item => item;
107
- const filter = typeof itemFilter === 'function' ? itemFilter : () => true;
108
-
109
- return filterRuntimeMenuModulesByType(runtimeMenus, menuType)
110
- .flatMap(module => (Array.isArray(module?.menus) ? module.menus : []))
111
- .map(item => mapper({...item}))
112
- .filter(Boolean)
113
- .filter(filter)
114
- .sort(sortRuntimeMenuItems)
115
- .map(item => ({
116
- route: item.route,
117
- icon: item.icon || 'circle',
118
- label: resolveRuntimeMenuLabel(item, global.t?.t),
119
- routeParams: item.routeParams,
120
- menuType: item.menuType,
121
- }))
122
- .filter(item => Boolean(item.route));
123
- }, [itemFilter, itemMapper, menuType, runtimeMenus]);
124
-
125
- const resolvedActiveRoute = resolveBottomNavigationRoute(
126
- routeAliases,
127
- activeRouteName,
128
- );
129
- const knownRoute = navItems.some(item => item.route === resolvedActiveRoute);
130
- const effectiveActiveRoute = knownRoute
131
- ? resolvedActiveRoute
132
- : navItems[0]?.route || activeRouteName;
133
-
134
- const isDisabled =
135
- typeof disabledOverride === 'boolean'
136
- ? disabledOverride
137
- : !currentCompany || Object.keys(currentCompany).length === 0;
138
-
139
- return (
140
- <BottomNavigationBar
141
- activeRouteName={effectiveActiveRoute}
142
- colors={colors}
143
- disabled={isDisabled}
144
- items={navItems}
145
- navigation={navigation}
146
- testID={testID}
147
- />
148
- );
149
- };
150
-
151
- export default RuntimeBottomNavigationBar;
82
+ let cancelled = false;
83
+ setRuntimeMenus([]);
84
+
85
+ api
86
+ .fetch('menus-people', {
87
+ params: {
88
+ myCompany: currentCompany.id,
89
+ appType,
90
+ menuType,
91
+ },
92
+ })
93
+ .then(result => {
94
+ if (!cancelled) {
95
+ setRuntimeMenus(
96
+ normalizeRuntimeMenuResponse(result, {
97
+ appType,
98
+ allowFallback: false,
99
+ }),
100
+ );
101
+ }
102
+ })
103
+ .catch(() => {
104
+ if (!cancelled) {
105
+ setRuntimeMenus([]);
106
+ }
107
+ });
108
+
109
+ return () => {
110
+ cancelled = true;
111
+ };
112
+ }, [
113
+ appType,
114
+ currentCompany?.id,
115
+ menuType,
116
+ preset,
117
+ presetKey,
118
+ ]);
119
+
120
+ const colors = useMemo(() => {
121
+ if (colorsOverride) {
122
+ return colorsOverride;
123
+ }
124
+
125
+ return {
126
+ ...themeColors,
127
+ ...(currentCompany?.theme?.colors || {}),
128
+ };
129
+ }, [colorsOverride, currentCompany?.theme?.colors, themeColors]);
130
+
131
+ const navItems = useMemo(() => {
132
+ const mapper = typeof itemMapper === 'function' ? itemMapper : item => item;
133
+ const filter = typeof itemFilter === 'function' ? itemFilter : () => true;
134
+
135
+ return filterRuntimeMenuModulesByType(runtimeMenus, menuType)
136
+ .flatMap(module => (Array.isArray(module?.menus) ? module.menus : []))
137
+ .map(item => mapper({...item}))
138
+ .filter(Boolean)
139
+ .filter(filter)
140
+ .sort(sortRuntimeMenuItems)
141
+ .map(item => ({
142
+ route: item.route,
143
+ icon: item.icon || 'circle',
144
+ label: resolveRuntimeMenuLabel(item, global.t?.t),
145
+ routeParams: item.routeParams,
146
+ menuType: item.menuType,
147
+ }))
148
+ .filter(item => Boolean(item.route));
149
+ }, [itemFilter, itemMapper, menuType, runtimeMenus]);
150
+
151
+ const resolvedActiveRoute = resolveBottomNavigationRoute(
152
+ routeAliases,
153
+ activeRouteName,
154
+ );
155
+ const knownRoute = navItems.some(item => item.route === resolvedActiveRoute);
156
+ const effectiveActiveRoute = knownRoute
157
+ ? resolvedActiveRoute
158
+ : navItems[0]?.route || activeRouteName;
159
+
160
+ const isDisabled =
161
+ typeof disabledOverride === 'boolean'
162
+ ? disabledOverride
163
+ : !currentCompany || Object.keys(currentCompany).length === 0;
164
+
165
+ return (
166
+ <BottomNavigationBar
167
+ activeRouteName={effectiveActiveRoute}
168
+ colors={colors}
169
+ disabled={isDisabled}
170
+ items={navItems}
171
+ navigation={navigation}
172
+ testID={testID}
173
+ useModernWebChromeProps={useModernWebChromeProps}
174
+ />
175
+ );
176
+ };
177
+
178
+ export default RuntimeBottomNavigationBar;
@@ -2,7 +2,6 @@ import React, {useEffect, useMemo, useState} from 'react';
2
2
  import {ActivityIndicator, Text, View, useWindowDimensions} from 'react-native';
3
3
  import {useStore, useStores} from '@store';
4
4
  import {useSafeAreaInsets} from 'react-native-safe-area-context';
5
- import {colors as runtimeColors} from '@controleonline/../../src/styles/colors';
6
5
  import {
7
6
  DEVICE_RUNTIME_DEBUG_INFO_ENABLED_KEY,
8
7
  isTruthyValue,
@@ -19,7 +18,13 @@ const ROTATION_INTERVAL_MS = 6000;
19
18
  const COMPACT_BREAKPOINT = 720;
20
19
  const MAX_INLINE_TEXT_LENGTH = 84;
21
20
 
22
- const RuntimeInfoFooter = ({appVersion, defaultCompany, device, colors}) => {
21
+ const RuntimeInfoFooter = ({
22
+ appVersion,
23
+ defaultCompany,
24
+ device,
25
+ colors,
26
+ useModernWebChromeProps = false,
27
+ }) => {
23
28
  const {width} = useWindowDimensions();
24
29
  const insets = useSafeAreaInsets();
25
30
  const [activeIndex, setActiveIndex] = useState(0);
@@ -110,7 +115,26 @@ const RuntimeInfoFooter = ({appVersion, defaultCompany, device, colors}) => {
110
115
  () => footerEntries.flatMap(entry => entry?.lines || []),
111
116
  [footerEntries],
112
117
  );
113
- const socketIndicatorColor = socketEntry?.indicatorColor;
118
+ const socketIndicatorColor = useMemo(() => {
119
+ const indicatorTone = String(socketEntry?.indicatorTone || '').trim();
120
+ if (!indicatorTone) {
121
+ return undefined;
122
+ }
123
+
124
+ if (indicatorTone === 'success') {
125
+ return colors?.success;
126
+ }
127
+
128
+ if (indicatorTone === 'warning') {
129
+ return colors?.warning;
130
+ }
131
+
132
+ if (indicatorTone === 'error') {
133
+ return colors?.error;
134
+ }
135
+
136
+ return undefined;
137
+ }, [colors?.error, colors?.success, colors?.warning, socketEntry?.indicatorTone]);
114
138
  const hasStoreLoading = useMemo(
115
139
  () =>
116
140
  Object.values(allStores || {}).some(
@@ -140,15 +164,19 @@ const RuntimeInfoFooter = ({appVersion, defaultCompany, device, colors}) => {
140
164
  if (entries.length === 0 && !showDebugInfo) {
141
165
  return null;
142
166
  }
143
-
167
+
144
168
  const displayedText = shouldRotate ? entries[activeIndex] : inlineText;
145
- const backgroundColor = colors?.background || runtimeColors.background;
146
- const borderColor = colors?.border || runtimeColors.border;
147
- const textColor = colors?.textSecondary || runtimeColors.textSecondary;
148
- const loadingColor = colors?.primary || runtimeColors.primary || textColor;
169
+ const backgroundColor = colors?.footerBackground;
170
+ const borderColor = colors?.footerBorder;
171
+ const textColor = colors?.footerText;
172
+ const loadingColor = colors?.footerLink;
173
+ const shellProps = useModernWebChromeProps ? {} : {pointerEvents: 'none'};
174
+ const shellStyle = useModernWebChromeProps
175
+ ? [styles.shell, {pointerEvents: 'none'}]
176
+ : styles.shell;
149
177
 
150
178
  return (
151
- <View pointerEvents="none" style={styles.shell}>
179
+ <View {...shellProps} style={shellStyle}>
152
180
  <View
153
181
  testID="runtime-info-footer"
154
182
  style={[