@controleonline/ui-common 1.2.87 → 1.2.89
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/workflows/integration-source-gate.yml +68 -0
- package/.github/workflows/manager-worker.yml +7 -156
- package/.github/workflows/publish-npm.yml +73 -27
- package/.github/workflows/pull-request-checks.yml +7 -5
- package/docs/technical/Device-Detail-Alias-UI-Sync.md +141 -0
- package/package.json +13 -8
- package/src/api/localDB.js +86 -131
- package/src/react/components/BottomNavigationBar.js +178 -174
- package/src/react/components/BottomNavigationBar.styles.js +139 -118
- package/src/react/components/DefaultProvider.native.js +427 -421
- package/src/react/components/DefaultProvider.web.js +131 -125
- package/src/react/components/RemoteCheckoutService.js +3 -3
- package/src/react/components/RuntimeFooterMarqueeText.js +88 -36
- package/src/react/components/RuntimeInfoFooter.js +76 -43
- package/src/react/components/RuntimeInfoFooter.styles.js +22 -14
- package/src/react/config/deviceConfigBootstrap.js +71 -233
- package/src/react/config/deviceConfigValues.js +238 -0
- package/src/react/pages/Devices/detail/DeviceChargePermissionSection.js +32 -0
- package/src/react/pages/Devices/detail/DeviceDetailAlertsCommandsSection.js +4 -22
- package/src/react/pages/Devices/detail/DeviceDetailMovementSections.js +6 -2
- package/src/react/pages/Devices/detail/DeviceDetailOrdersPrintSection.js +4 -0
- package/src/react/pages/Devices/detail/DeviceDetailPdvConfigSection.js +7 -0
- package/src/react/pages/Devices/detail/DeviceDetailScreen.js +24 -335
- package/src/react/pages/Devices/detail/createDeviceDetailContext.js +20 -0
- package/src/react/pages/Devices/detail/deviceDetailHelpers.js +2 -11
- package/src/react/pages/Devices/detail/useDeviceDetailActions.js +11 -36
- package/src/react/pages/Devices/detail/useDeviceDetailLoaders.js +129 -37
- package/src/react/pages/Devices/detail/useDeviceDetailSaves.js +11 -38
- package/src/react/pages/Devices/detail/useDeviceDetailStateA.js +9 -28
- package/src/react/pages/IntegrationConfigFields.js +1 -0
- package/src/react/pages/IntegrationConfigPage.js +101 -45
- package/src/react/pages/IntegrationConfigPage.utils.js +21 -13
- package/src/react/pages/fetchPeopleConfigs.js +21 -0
- package/src/react/pages/integrationsCatalog.js +15 -110
- package/src/react/services/Cielo/Cielo.js +9 -9
- package/src/react/services/Getnet/Getnet.web.js +25 -0
- package/src/react/utils/companyAuthority.js +36 -0
- package/src/react/utils/confirmAction.js +12 -0
- package/src/react/utils/fileUrl.js +14 -5
- package/src/react/utils/paymentDevices.js +375 -270
- package/src/react/utils/printerDevices.js +2 -2
- package/src/react/utils/runtimeFooter.js +178 -224
- package/src/react/utils/runtimeFooterText.js +160 -0
- package/src/react/utils/runtimeLanguage.js +5 -5
- package/src/react/utils/runtimeZoom.js +29 -5
- package/src/react/utils/shopFranchises.js +167 -12
- package/src/react/utils/storeColumns.js +235 -217
- package/src/react/utils/systemErrorMessage.js +2 -1
- package/src/store/integration/index.js +43 -0
- package/src/tests/browser/manager/device-detail-apply-config-defined.spec.js +31 -0
- package/src/tests/browser/manager/device-detail-composition.spec.js +295 -0
- package/src/tests/browser/manager/device-detail-copy-config.spec.js +11 -1
- package/src/tests/browser/manager/device-detail-pdv-current-company.spec.js +273 -0
- package/src/tests/browser/manager/runtime-footer-rotation.spec.js +397 -0
- package/src/tests/react/components/DefaultProviderAuthority.test.js +28 -0
- package/src/tests/react/components/RuntimeFooterMarqueeText.build.test.js +29 -0
- package/src/tests/react/config/deviceConfigBootstrap.test.js +24 -1
- package/src/tests/react/pages/DeviceChargePermissionSection.test.js +42 -0
- package/src/tests/react/pages/applyCurrentDeviceConfig.test.js +85 -0
- package/src/tests/react/pages/deviceDetailComposition.test.js +65 -0
- package/src/tests/react/pages/deviceDetailHookDependencies.test.mjs +31 -0
- package/src/tests/react/pages/deviceDetailLoaderDependencies.test.mjs +28 -0
- package/src/tests/react/pages/receitaFederalIntegrationContract.test.mjs +27 -6
- package/src/tests/react/services/Cielo.test.js +2 -2
- package/src/tests/react/utils/companyAuthority.test.js +53 -0
- package/src/tests/react/utils/formatter.test.mjs +6 -0
- package/src/tests/react/utils/paymentDevices.test.js +72 -0
- package/src/tests/react/utils/runtimeFooter.test.js +35 -0
- package/src/tests/react/utils/runtimeFooterText.test.js +88 -0
- package/src/tests/react/utils/runtimeLanguage.test.js +4 -4
- package/src/tests/react/utils/runtimeZoom.test.js +20 -0
- package/src/tests/react/utils/shopFranchises.test.js +32 -13
- package/src/tests/react/utils/translate.test.mjs +6 -6
- package/src/utils/formatter.js +7 -3
- package/src/utils/translate.js +16 -16
- package/src/utils/translatePending.js +6 -6
- package/src/utils/translateStorage.js +2 -2
package/src/api/localDB.js
CHANGED
|
@@ -1,131 +1,86 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const DB_NAME =
|
|
4
|
-
|
|
5
|
-
export default class localDB {
|
|
6
|
-
constructor(state) {
|
|
7
|
-
this.state = state;
|
|
8
|
-
|
|
9
|
-
this.
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async initDB() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const db = await this.checkAndGetDB();
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
await
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
const db = await this.checkAndGetDB();
|
|
90
|
-
return db.get(this.state.resourceEndpoint, id);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async saveItems(items) {
|
|
94
|
-
const db = await this.checkAndGetDB();
|
|
95
|
-
const tx = db.transaction(this.state.resourceEndpoint, "readwrite");
|
|
96
|
-
const store = tx.objectStore(this.state.resourceEndpoint);
|
|
97
|
-
await Promise.all(items.map((item) => store.put(item)));
|
|
98
|
-
await tx.done;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async saveItem(item) {
|
|
102
|
-
const db = await this.checkAndGetDB();
|
|
103
|
-
return db.put(this.state.resourceEndpoint, item);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async getItemsByFilters() {
|
|
107
|
-
if (!(await this.storeExists())) {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
const db = await this.checkAndGetDB();
|
|
111
|
-
if (Object.keys(this.state.filters).length === 0) {
|
|
112
|
-
return this.getAll();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const filterPromises = Object.entries(this.state.filters).map(
|
|
116
|
-
async ([key, value]) => {
|
|
117
|
-
const column = this.state.columns.find((col) => col.name === key);
|
|
118
|
-
if (column && (column.sortable || column.externalFilter === false)) {
|
|
119
|
-
return this.getItemsByColumn(key, value);
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const filterResults = await Promise.all(filterPromises);
|
|
126
|
-
return filterResults.reduce((acc, curr) => {
|
|
127
|
-
if (!acc || acc.length === 0) return curr;
|
|
128
|
-
return acc.filter((item) => curr.some((result) => result.id === item.id));
|
|
129
|
-
}, []);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
1
|
+
import {openDB} from 'idb';
|
|
2
|
+
|
|
3
|
+
const DB_NAME = 'ControleOnline';
|
|
4
|
+
|
|
5
|
+
export default class localDB {
|
|
6
|
+
constructor(state) {
|
|
7
|
+
this.state = state;
|
|
8
|
+
this.db = null;
|
|
9
|
+
this.opening = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async initDB() {
|
|
13
|
+
const endpoint = this.state.resourceEndpoint;
|
|
14
|
+
const upgrade = db => {
|
|
15
|
+
if (db.objectStoreNames.contains(endpoint)) return;
|
|
16
|
+
const store = db.createObjectStore(endpoint, {keyPath: 'id'});
|
|
17
|
+
(this.state.columns || []).forEach(column => {
|
|
18
|
+
if (column.name && (column.sortable || column.externalFilter === false)) {
|
|
19
|
+
store.createIndex(column.name, column.name, {unique: false});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
const blocking = () => { this.db?.close(); this.db = null; };
|
|
24
|
+
let db = await openDB(DB_NAME, undefined, {upgrade, blocking});
|
|
25
|
+
if (!db.objectStoreNames.contains(endpoint)) {
|
|
26
|
+
const version = db.version + 1;
|
|
27
|
+
db.close();
|
|
28
|
+
db = await openDB(DB_NAME, version, {upgrade, blocking});
|
|
29
|
+
}
|
|
30
|
+
this.db = db;
|
|
31
|
+
return db;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async getCurrentVersion() {
|
|
35
|
+
return (await this.checkAndGetDB()).version;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
checkAndGetDB() {
|
|
39
|
+
if (this.db) return Promise.resolve(this.db);
|
|
40
|
+
if (!this.opening) {
|
|
41
|
+
this.opening = this.initDB().finally(() => { this.opening = null; });
|
|
42
|
+
}
|
|
43
|
+
return this.opening;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async storeExists() {
|
|
47
|
+
return (await this.checkAndGetDB()).objectStoreNames.contains(this.state.resourceEndpoint);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getAll() {
|
|
51
|
+
return (await this.checkAndGetDB()).getAll(this.state.resourceEndpoint);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getItemsByColumn(columnName, value) {
|
|
55
|
+
const db = await this.checkAndGetDB();
|
|
56
|
+
const tx = db.transaction(this.state.resourceEndpoint, 'readonly');
|
|
57
|
+
if (!tx.store.indexNames.contains(columnName)) return [];
|
|
58
|
+
const items = await tx.store.index(columnName).getAll(value);
|
|
59
|
+
await tx.done;
|
|
60
|
+
return items;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async get(id) {
|
|
64
|
+
return (await this.checkAndGetDB()).get(this.state.resourceEndpoint, id);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async saveItems(items) {
|
|
68
|
+
const db = await this.checkAndGetDB();
|
|
69
|
+
const tx = db.transaction(this.state.resourceEndpoint, 'readwrite');
|
|
70
|
+
await Promise.all(items.map(item => tx.store.put(item)));
|
|
71
|
+
await tx.done;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async saveItem(item) {
|
|
75
|
+
return (await this.checkAndGetDB()).put(this.state.resourceEndpoint, item);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async getItemsByFilters() {
|
|
79
|
+
const filters = Object.entries(this.state.filters || {});
|
|
80
|
+
if (!filters.length) return this.getAll();
|
|
81
|
+
const matches = await Promise.all(filters.map(([key, value]) =>
|
|
82
|
+
this.getItemsByColumn(key, value)));
|
|
83
|
+
return matches.reduce((items, next) => items.filter(item =>
|
|
84
|
+
next.some(result => result.id === item.id)));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -1,175 +1,179 @@
|
|
|
1
|
-
import React, {useLayoutEffect, useMemo} from 'react';
|
|
2
|
-
import {Pressable, Text, View} from 'react-native';
|
|
3
|
-
import Icon from 'react-native-vector-icons/Feather';
|
|
4
|
-
import {useTheme} from './DefaultProvider';
|
|
5
|
-
import RuntimeInfoFooter from './RuntimeInfoFooter';
|
|
1
|
+
import React, {useLayoutEffect, useMemo} from 'react';
|
|
2
|
+
import {Pressable, Text, View} from 'react-native';
|
|
3
|
+
import Icon from 'react-native-vector-icons/Feather';
|
|
4
|
+
import {useTheme} from './DefaultProvider';
|
|
5
|
+
import RuntimeInfoFooter from './RuntimeInfoFooter';
|
|
6
6
|
import {resolveMenuRouteParams} from '../utils/menuNavigation';
|
|
7
|
-
import createStyles from './BottomNavigationBar.styles';
|
|
8
|
-
|
|
9
|
-
const BottomNavigationBar = ({
|
|
10
|
-
navigation,
|
|
11
|
-
items = [],
|
|
12
|
-
activeRouteName,
|
|
13
|
-
disabled = false,
|
|
14
|
-
colors = {},
|
|
15
|
-
testID = 'bottom-navigation',
|
|
16
|
-
useModernWebChromeProps = false,
|
|
17
|
-
}) => {
|
|
18
|
-
const theme = useTheme?.() || {};
|
|
19
|
-
const runtimeFooter = theme?.runtimeFooter || null;
|
|
20
|
-
const registerBottomNavigation =
|
|
21
|
-
theme?.bottomChrome?.registerBottomNavigation || null;
|
|
22
|
-
const activeBackground = colors.navigationActiveBackground;
|
|
23
|
-
const activeBorder = colors.navigationActiveBorder;
|
|
24
|
-
const activeIcon = colors.navigationActiveIcon;
|
|
25
|
-
const activeText = colors.navigationActiveText;
|
|
26
|
-
const dockBackground = colors.navigationBackground;
|
|
27
|
-
const dockBorder = colors.navigationBorder;
|
|
28
|
-
const dockShadow = colors.navigationShadow;
|
|
29
|
-
const inactiveIcon = colors.navigationIcon;
|
|
30
|
-
const inactiveText = colors.navigationText;
|
|
31
|
-
|
|
32
|
-
const styles = useMemo(
|
|
33
|
-
() =>
|
|
34
|
-
createStyles({
|
|
35
|
-
activeBackground,
|
|
36
|
-
dockBackground,
|
|
37
|
-
dockBorder,
|
|
38
|
-
dockShadow,
|
|
39
|
-
activeBorder,
|
|
40
|
-
useModernWebChromeProps,
|
|
41
|
-
}),
|
|
42
|
-
[
|
|
43
|
-
activeBackground,
|
|
44
|
-
activeBorder,
|
|
45
|
-
dockBackground,
|
|
46
|
-
dockBorder,
|
|
47
|
-
dockShadow,
|
|
48
|
-
useModernWebChromeProps,
|
|
49
|
-
],
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
const resolveItemColors = ({isActive, isDisabled}) => {
|
|
53
|
-
if (isActive) {
|
|
54
|
-
return {
|
|
55
|
-
iconColor: activeIcon,
|
|
56
|
-
textColor: activeText,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (isDisabled) {
|
|
61
|
-
return {
|
|
62
|
-
iconColor: colors.navigationDisabledIcon,
|
|
63
|
-
textColor: colors.navigationDisabledText,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
iconColor: inactiveIcon,
|
|
69
|
-
textColor: inactiveText,
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const resolveItemStateStyles = ({isActive, isDisabled}) => [
|
|
74
|
-
styles.item,
|
|
75
|
-
isActive && styles.itemActive,
|
|
76
|
-
isDisabled && styles.itemDisabled,
|
|
77
|
-
isDisabled && {
|
|
78
|
-
backgroundColor: colors.navigationDisabledBackground,
|
|
79
|
-
borderColor: colors.navigationDisabledBorder,
|
|
80
|
-
},
|
|
81
|
-
];
|
|
82
|
-
|
|
83
|
-
const resolvePressedStyles = ({pressed, isDisabled}) =>
|
|
84
|
-
pressed && !isDisabled
|
|
85
|
-
? [
|
|
86
|
-
styles.itemPressed,
|
|
87
|
-
]
|
|
88
|
-
: [];
|
|
89
|
-
|
|
90
|
-
useLayoutEffect(() => {
|
|
91
|
-
if (typeof registerBottomNavigation !== 'function') {
|
|
92
|
-
return undefined;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return registerBottomNavigation();
|
|
96
|
-
}, [registerBottomNavigation]);
|
|
97
|
-
|
|
98
|
-
const routeItems = Array.isArray(items) ? items : [];
|
|
99
|
-
const knownRoute = routeItems.some(item => item?.route === activeRouteName);
|
|
100
|
-
const effectiveActiveRoute = knownRoute
|
|
101
|
-
? activeRouteName
|
|
102
|
-
: routeItems[0]?.route || '';
|
|
103
|
-
|
|
104
|
-
const navigateTo = item => {
|
|
105
|
-
try {
|
|
106
|
-
navigation?.navigate?.(item?.route, resolveMenuRouteParams(item?.routeParams));
|
|
107
|
-
} catch {
|
|
108
|
-
// Keep the footer stable if a route is unavailable in the current app flavor.
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const hostProps = useModernWebChromeProps
|
|
113
|
-
? {}
|
|
114
|
-
: {pointerEvents: 'box-none'};
|
|
115
|
-
const hostStyle = useModernWebChromeProps
|
|
116
|
-
? [styles.host, styles.hostPointerEventsBoxNone]
|
|
117
|
-
: styles.host;
|
|
118
|
-
const footerProps = {
|
|
119
|
-
appVersion: runtimeFooter?.appVersion,
|
|
120
|
-
colors: runtimeFooter?.colors || {},
|
|
121
|
-
|
|
122
|
-
device: runtimeFooter?.device,
|
|
123
|
-
useModernWebChromeProps,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<View {...hostProps} style={hostStyle}>
|
|
128
|
-
<View style={styles.stack}>
|
|
129
|
-
<View style={styles.dock} testID={testID}>
|
|
130
|
-
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
7
|
+
import createStyles from './BottomNavigationBar.styles';
|
|
8
|
+
|
|
9
|
+
const BottomNavigationBar = ({
|
|
10
|
+
navigation,
|
|
11
|
+
items = [],
|
|
12
|
+
activeRouteName,
|
|
13
|
+
disabled = false,
|
|
14
|
+
colors = {},
|
|
15
|
+
testID = 'bottom-navigation',
|
|
16
|
+
useModernWebChromeProps = false,
|
|
17
|
+
}) => {
|
|
18
|
+
const theme = useTheme?.() || {};
|
|
19
|
+
const runtimeFooter = theme?.runtimeFooter || null;
|
|
20
|
+
const registerBottomNavigation =
|
|
21
|
+
theme?.bottomChrome?.registerBottomNavigation || null;
|
|
22
|
+
const activeBackground = colors.navigationActiveBackground;
|
|
23
|
+
const activeBorder = colors.navigationActiveBorder;
|
|
24
|
+
const activeIcon = colors.navigationActiveIcon;
|
|
25
|
+
const activeText = colors.navigationActiveText;
|
|
26
|
+
const dockBackground = colors.navigationBackground;
|
|
27
|
+
const dockBorder = colors.navigationBorder;
|
|
28
|
+
const dockShadow = colors.navigationShadow;
|
|
29
|
+
const inactiveIcon = colors.navigationIcon;
|
|
30
|
+
const inactiveText = colors.navigationText;
|
|
31
|
+
|
|
32
|
+
const styles = useMemo(
|
|
33
|
+
() =>
|
|
34
|
+
createStyles({
|
|
35
|
+
activeBackground,
|
|
36
|
+
dockBackground,
|
|
37
|
+
dockBorder,
|
|
38
|
+
dockShadow,
|
|
39
|
+
activeBorder,
|
|
40
|
+
useModernWebChromeProps,
|
|
41
|
+
}),
|
|
42
|
+
[
|
|
43
|
+
activeBackground,
|
|
44
|
+
activeBorder,
|
|
45
|
+
dockBackground,
|
|
46
|
+
dockBorder,
|
|
47
|
+
dockShadow,
|
|
48
|
+
useModernWebChromeProps,
|
|
49
|
+
],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const resolveItemColors = ({isActive, isDisabled}) => {
|
|
53
|
+
if (isActive) {
|
|
54
|
+
return {
|
|
55
|
+
iconColor: activeIcon,
|
|
56
|
+
textColor: activeText,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isDisabled) {
|
|
61
|
+
return {
|
|
62
|
+
iconColor: colors.navigationDisabledIcon,
|
|
63
|
+
textColor: colors.navigationDisabledText,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
iconColor: inactiveIcon,
|
|
69
|
+
textColor: inactiveText,
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const resolveItemStateStyles = ({isActive, isDisabled}) => [
|
|
74
|
+
styles.item,
|
|
75
|
+
isActive && styles.itemActive,
|
|
76
|
+
isDisabled && styles.itemDisabled,
|
|
77
|
+
isDisabled && {
|
|
78
|
+
backgroundColor: colors.navigationDisabledBackground,
|
|
79
|
+
borderColor: colors.navigationDisabledBorder,
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
const resolvePressedStyles = ({pressed, isDisabled}) =>
|
|
84
|
+
pressed && !isDisabled
|
|
85
|
+
? [
|
|
86
|
+
styles.itemPressed,
|
|
87
|
+
]
|
|
88
|
+
: [];
|
|
89
|
+
|
|
90
|
+
useLayoutEffect(() => {
|
|
91
|
+
if (typeof registerBottomNavigation !== 'function') {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return registerBottomNavigation();
|
|
96
|
+
}, [registerBottomNavigation]);
|
|
97
|
+
|
|
98
|
+
const routeItems = Array.isArray(items) ? items : [];
|
|
99
|
+
const knownRoute = routeItems.some(item => item?.route === activeRouteName);
|
|
100
|
+
const effectiveActiveRoute = knownRoute
|
|
101
|
+
? activeRouteName
|
|
102
|
+
: routeItems[0]?.route || '';
|
|
103
|
+
|
|
104
|
+
const navigateTo = item => {
|
|
105
|
+
try {
|
|
106
|
+
navigation?.navigate?.(item?.route, resolveMenuRouteParams(item?.routeParams));
|
|
107
|
+
} catch {
|
|
108
|
+
// Keep the footer stable if a route is unavailable in the current app flavor.
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const hostProps = useModernWebChromeProps
|
|
113
|
+
? {}
|
|
114
|
+
: {pointerEvents: 'box-none'};
|
|
115
|
+
const hostStyle = useModernWebChromeProps
|
|
116
|
+
? [styles.host, styles.hostPointerEventsBoxNone]
|
|
117
|
+
: styles.host;
|
|
118
|
+
const footerProps = {
|
|
119
|
+
appVersion: runtimeFooter?.appVersion,
|
|
120
|
+
colors: runtimeFooter?.colors || {},
|
|
121
|
+
mainCompany: runtimeFooter?.mainCompany,
|
|
122
|
+
device: runtimeFooter?.device,
|
|
123
|
+
useModernWebChromeProps,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<View {...hostProps} style={hostStyle}>
|
|
128
|
+
<View style={styles.stack}>
|
|
129
|
+
<View style={styles.dock} testID={testID}>
|
|
130
|
+
<View style={styles.itemsRow}>
|
|
131
|
+
{routeItems.map(item => {
|
|
132
|
+
const isActive = effectiveActiveRoute === item.route;
|
|
133
|
+
const isDisabled = disabled || item.disabled;
|
|
134
|
+
const iconSize = item.iconSize || 18;
|
|
135
|
+
const {iconColor, textColor} = resolveItemColors({
|
|
136
|
+
isActive,
|
|
137
|
+
isDisabled,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<Pressable
|
|
142
|
+
key={item.route}
|
|
143
|
+
accessibilityRole="button"
|
|
144
|
+
disabled={isDisabled}
|
|
145
|
+
onPress={() => navigateTo(item)}
|
|
146
|
+
style={({pressed}) => [
|
|
147
|
+
...resolveItemStateStyles({isActive, isDisabled}),
|
|
148
|
+
...resolvePressedStyles({pressed, isDisabled}),
|
|
149
|
+
]}>
|
|
150
|
+
<View style={styles.iconWrap}>
|
|
151
|
+
<Icon color={iconColor} name={item.icon} size={iconSize} />
|
|
152
|
+
</View>
|
|
153
|
+
<Text
|
|
154
|
+
numberOfLines={1}
|
|
155
|
+
style={[
|
|
156
|
+
styles.itemLabel,
|
|
157
|
+
{
|
|
158
|
+
color: textColor,
|
|
159
|
+
},
|
|
160
|
+
]}>
|
|
161
|
+
{item.label}
|
|
162
|
+
</Text>
|
|
163
|
+
</Pressable>
|
|
164
|
+
);
|
|
165
|
+
})}
|
|
166
|
+
</View>
|
|
167
|
+
{/* app-community#384: texto do rodapé DEPOIS dos botões (não antes) */}
|
|
168
|
+
{runtimeFooter ? (
|
|
169
|
+
<View style={styles.footerSlot} testID="bottom-navigation-footer-slot">
|
|
170
|
+
<RuntimeInfoFooter {...footerProps} />
|
|
171
|
+
</View>
|
|
172
|
+
) : null}
|
|
173
|
+
</View>
|
|
174
|
+
</View>
|
|
175
|
+
</View>
|
|
176
|
+
);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export default BottomNavigationBar;
|