@controleonline/ui-common 1.2.70 → 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.
Files changed (188) hide show
  1. package/.github/actions/workers/manager/action.yml +147 -0
  2. package/.github/actions/workers/qa/action.yml +44 -0
  3. package/.github/actions/workers/security/action.yml +44 -0
  4. package/.github/actions/workers/technical-documenter/action.yml +51 -0
  5. package/.github/workflows/manager-worker.yml +168 -0
  6. package/.github/workflows/publish-npm.yml +45 -0
  7. package/.gitmodules +3 -0
  8. package/AGENTS.md +6 -0
  9. package/README.md +14 -0
  10. package/package.json +32 -28
  11. package/src/api/fetch.js +1 -1
  12. package/src/api/index.js +328 -58
  13. package/src/react/components/AddImportModal.js +95 -111
  14. package/src/react/components/AnimatedModal.js +171 -0
  15. package/src/react/components/AnimatedModal.styles.js +21 -0
  16. package/src/react/components/AppTypeSwitcher.js +164 -0
  17. package/src/react/components/AppTypeSwitcher.styles.js +109 -0
  18. package/src/react/components/BackgroundRuntimeBridge.js +5 -4
  19. package/src/react/components/BottomNavigationBar.config.js +211 -231
  20. package/src/react/components/BottomNavigationBar.js +86 -31
  21. package/src/react/components/BottomNavigationBar.styles.js +118 -110
  22. package/src/react/components/CategoryForm.js +52 -35
  23. package/src/react/components/DefaultProvider.native.js +194 -156
  24. package/src/react/components/DefaultProvider.web.js +188 -112
  25. package/src/react/components/DeliveryPushBridge.native.js +2 -2
  26. package/src/react/components/DeviceAlertSoundService.js +3 -3
  27. package/src/react/components/KioskModeBridge.js +2 -2
  28. package/src/react/components/LauncherModeBridge.js +2 -2
  29. package/src/react/components/ManagerPushBridge.native.js +2 -2
  30. package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
  31. package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
  32. package/src/react/components/RemoteCheckoutService.js +28 -20
  33. package/src/react/components/RuntimeBottomNavigationBar.js +146 -119
  34. package/src/react/components/RuntimeInfoFooter.js +137 -45
  35. package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
  36. package/src/react/components/StateStore.js +258 -0
  37. package/src/react/components/UnifiedPaymentBar.js +7 -4
  38. package/src/react/components/UserAvatar.js +160 -0
  39. package/src/react/components/WebsocketListener.native.js +11 -11
  40. package/src/react/components/integrations/IntegrationHero/index.js +48 -0
  41. package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
  42. package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
  43. package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
  44. package/src/react/config/deviceConfigBootstrap.js +71 -30
  45. package/src/react/css/orders.js +72 -0
  46. package/src/react/pages/Connections.js +229 -0
  47. package/src/react/pages/Connections.styles.js +222 -0
  48. package/src/react/pages/DeviceDetailPage.js +2814 -0
  49. package/src/react/pages/DeviceDetailPage.styles.js +308 -0
  50. package/src/react/pages/Devices/currentDevice.js +194 -0
  51. package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
  52. package/src/react/pages/Devices/deviceTypes/all.js +23 -0
  53. package/src/react/pages/Devices/deviceTypes/device.js +25 -0
  54. package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
  55. package/src/react/pages/Devices/deviceTypes/display.js +26 -0
  56. package/src/react/pages/Devices/deviceTypes/index.js +145 -0
  57. package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
  58. package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
  59. package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
  60. package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
  61. package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
  62. package/src/react/pages/Devices.js +183 -0
  63. package/src/react/pages/Devices.styles.js +353 -0
  64. package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
  65. package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
  66. package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
  67. package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
  68. package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
  69. package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
  70. package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
  71. package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
  72. package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
  73. package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
  74. package/src/react/pages/Food99IntegrationPage.js +1 -0
  75. package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
  76. package/src/react/pages/GenericLogPage.js +42 -167
  77. package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
  78. package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
  79. package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
  80. package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
  81. package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
  82. package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
  83. package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
  84. package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
  85. package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
  86. package/src/react/pages/IFoodIntegrationPage.js +1 -0
  87. package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
  88. package/src/react/pages/Imports.js +214 -166
  89. package/src/react/pages/IntegrationConfigPage.js +744 -0
  90. package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
  91. package/src/react/pages/Integrations.js +299 -0
  92. package/src/react/pages/Integrations.styles.js +130 -0
  93. package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
  94. package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
  95. package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
  96. package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
  97. package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
  98. package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
  99. package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
  100. package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
  101. package/src/react/pages/PrinterDeviceFormPage.js +521 -0
  102. package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
  103. package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +484 -454
  104. package/src/react/pages/SettingsPage/index.js +1266 -1167
  105. package/src/react/pages/WhatsAppConnectionPage.js +459 -0
  106. package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
  107. package/src/react/pages/integrationsCatalog.js +399 -0
  108. package/src/react/print/providers/local.js +1 -1
  109. package/src/react/router/publicRoutes.js +25 -0
  110. package/src/react/services/Cielo/Checkout.js +39 -0
  111. package/src/react/services/Cielo/Cielo.js +193 -0
  112. package/src/react/services/Cielo/Print.js +7 -0
  113. package/src/react/services/InfinitePay/Checkout.js +33 -0
  114. package/src/react/services/InfinitePay/InfinitePay.js +24 -0
  115. package/src/react/{utils → services}/paymentGatewayExecution.js +91 -91
  116. package/src/react/styles/global.js +115 -0
  117. package/src/react/utils/categoryContexts.js +46 -0
  118. package/src/react/utils/entityDisplay.js +222 -217
  119. package/src/react/utils/fileUrl.js +201 -16
  120. package/src/react/utils/integrationPage.js +16 -0
  121. package/src/react/utils/menuNavigation.js +31 -0
  122. package/src/react/utils/orderIdentity.js +277 -0
  123. package/src/react/utils/remotePayment.js +115 -61
  124. package/src/react/utils/runtimeFooter.js +40 -22
  125. package/src/react/utils/runtimeLanguage.js +50 -9
  126. package/src/react/utils/runtimeMenu.js +190 -98
  127. package/src/react/utils/runtimeZoom.js +43 -0
  128. package/src/react/utils/shopConfig.js +72 -34
  129. package/src/react/utils/shopFranchises.js +182 -23
  130. package/src/react/utils/socketRuntimePipeline.js +14 -14
  131. package/src/react/utils/storeColumns.js +23 -4
  132. package/src/react/utils/userAvatar.js +104 -0
  133. package/src/store/categories/index.js +48 -20
  134. package/src/store/configs/index.js +2 -2
  135. package/src/store/device_config/index.js +62 -21
  136. package/src/store/entity_log/index.js +22 -1
  137. package/src/store/imports/customActions.js +51 -0
  138. package/src/store/imports/index.js +89 -88
  139. package/src/store/status/index.js +11 -11
  140. package/src/store/themes/index.js +22 -0
  141. package/src/store/timezones/index.js +3 -1
  142. package/src/tests/browser/manager/connections.spec.js +143 -0
  143. package/src/tests/browser/manager/devices-current.spec.js +343 -0
  144. package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
  145. package/src/tests/react/api/deviceHeaders.test.js +114 -0
  146. package/src/tests/react/api/loadSmokeIndex.test.js +75 -0
  147. package/src/tests/react/components/AddImportModal.test.js +166 -0
  148. package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
  149. package/src/tests/react/components/UserAvatar.test.js +52 -0
  150. package/src/tests/react/config/deviceConfigBootstrap.test.js +47 -0
  151. package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
  152. package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
  153. package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
  154. package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
  155. package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
  156. package/src/tests/react/print/localPrintProvider.test.js +1 -1
  157. package/src/tests/react/services/Cielo.test.js +190 -0
  158. package/src/tests/react/store/categoriesOrdering.test.js +26 -0
  159. package/src/tests/react/utils/appDomain.test.js +62 -0
  160. package/src/tests/react/utils/entityDisplay.test.js +2 -2
  161. package/src/tests/react/utils/fileUrl.test.js +62 -0
  162. package/src/tests/react/utils/formatter.test.mjs +33 -0
  163. package/src/tests/react/utils/importStatus.test.js +2 -2
  164. package/src/tests/react/utils/orderIdentity.test.js +139 -0
  165. package/src/tests/react/utils/remotePayment.test.js +62 -0
  166. package/src/tests/react/utils/runtimeFooter.test.js +32 -9
  167. package/src/tests/react/utils/runtimeLanguage.test.js +80 -10
  168. package/src/tests/react/utils/runtimeMenu.test.js +195 -111
  169. package/src/tests/react/utils/runtimeZoom.test.js +38 -0
  170. package/src/tests/react/utils/shopConfig.test.js +75 -0
  171. package/src/tests/react/utils/shopFranchises.test.js +122 -12
  172. package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
  173. package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
  174. package/src/tests/react/utils/translate.test.mjs +252 -396
  175. package/src/tests/react/utils/userAvatar.test.js +63 -0
  176. package/src/utils/appDomain.js +15 -4
  177. package/src/utils/formatter.js +122 -16
  178. package/src/utils/integrationConfigs.js +1 -0
  179. package/src/utils/translate.js +277 -398
  180. package/src/utils/translateDiscovery.js +96 -0
  181. package/src/utils/translateNormalize.js +33 -0
  182. package/src/utils/translatePending.js +92 -0
  183. package/src/utils/translateStorage.js +142 -0
  184. package/.github/agents/developer.agent.md +0 -30
  185. package/.github/agents/devops.agent.md +0 -30
  186. package/.github/agents/qa.agent.md +0 -30
  187. package/.github/agents/security.agent.md +0 -30
  188. package/.github/workflows/npmjs.yml +0 -35
@@ -0,0 +1,171 @@
1
+ import React, {useEffect, useRef, useState} from 'react';
2
+ import {
3
+ Animated,
4
+ Dimensions,
5
+ Keyboard,
6
+ KeyboardAvoidingView,
7
+ Modal,
8
+ Platform,
9
+ StyleSheet,
10
+ Text,
11
+ } from 'react-native';
12
+ import {GestureHandlerRootView} from 'react-native-gesture-handler';
13
+ import {toast, Toasts} from '@backpackapp-io/react-native-toast';
14
+ import styles from './AnimatedModal.styles';
15
+ import {
16
+ TOAST_EXTRA_INSETS,
17
+ TOAST_MODAL_COUNT_KEY,
18
+ TOAST_PROVIDER_KEYS,
19
+ } from './toastConfig';
20
+
21
+ const {height: SCREEN_HEIGHT} = Dimensions.get('window');
22
+
23
+ const incrementModalToastDepth = () => {
24
+ const currentDepth = Number(global?.[TOAST_MODAL_COUNT_KEY] || 0);
25
+ global[TOAST_MODAL_COUNT_KEY] = currentDepth + 1;
26
+ };
27
+
28
+ const decrementModalToastDepth = () => {
29
+ const currentDepth = Number(global?.[TOAST_MODAL_COUNT_KEY] || 0);
30
+ global[TOAST_MODAL_COUNT_KEY] = Math.max(0, currentDepth - 1);
31
+ };
32
+
33
+ /**
34
+ * Modal com overlay aparecendo na hora e apenas o conteúdo subindo de baixo.
35
+ */
36
+ export default function AnimatedModal({
37
+ visible,
38
+ onRequestClose,
39
+ children,
40
+ style,
41
+ }) {
42
+ const [showing, setShowing] = useState(visible);
43
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
44
+ const overlayOpacity = useRef(new Animated.Value(0)).current;
45
+ const slideY = useRef(new Animated.Value(SCREEN_HEIGHT)).current;
46
+
47
+ useEffect(() => {
48
+ if (visible) {
49
+ setShowing(true);
50
+ slideY.setValue(SCREEN_HEIGHT);
51
+ overlayOpacity.setValue(0);
52
+
53
+ Animated.parallel([
54
+ Animated.spring(slideY, {
55
+ toValue: 0,
56
+ damping: 24,
57
+ stiffness: 300,
58
+ useNativeDriver: true,
59
+ }),
60
+ Animated.timing(overlayOpacity, {
61
+ toValue: 1,
62
+ duration: 300,
63
+ useNativeDriver: true,
64
+ }),
65
+ ]).start();
66
+ }
67
+ }, [visible, overlayOpacity, slideY]);
68
+
69
+ useEffect(() => {
70
+ if (!visible && showing) {
71
+ Animated.parallel([
72
+ Animated.timing(overlayOpacity, {
73
+ toValue: 0,
74
+ duration: 150,
75
+ useNativeDriver: true,
76
+ }),
77
+ Animated.timing(slideY, {
78
+ toValue: SCREEN_HEIGHT,
79
+ duration: 200,
80
+ useNativeDriver: true,
81
+ }),
82
+ ]).start(() => {
83
+ setShowing(false);
84
+ setKeyboardHeight(0);
85
+ onRequestClose?.();
86
+ });
87
+ }
88
+ }, [visible, showing, overlayOpacity, slideY, onRequestClose]);
89
+
90
+ useEffect(() => {
91
+ if (Platform.OS !== 'android') {
92
+ return undefined;
93
+ }
94
+
95
+ const showSub = Keyboard.addListener('keyboardDidShow', event => {
96
+ setKeyboardHeight(event?.endCoordinates?.height || 0);
97
+ });
98
+ const hideSub = Keyboard.addListener('keyboardDidHide', () => {
99
+ setKeyboardHeight(0);
100
+ });
101
+
102
+ return () => {
103
+ showSub.remove();
104
+ hideSub.remove();
105
+ };
106
+ }, []);
107
+
108
+ useEffect(() => {
109
+ if (!visible) {
110
+ setKeyboardHeight(0);
111
+ }
112
+ }, [visible]);
113
+
114
+ useEffect(() => {
115
+ if (!showing) {
116
+ return undefined;
117
+ }
118
+
119
+ incrementModalToastDepth();
120
+ return () => {
121
+ decrementModalToastDepth();
122
+ };
123
+ }, [showing]);
124
+
125
+ const overlayStyle = [
126
+ styles.overlay,
127
+ style,
128
+ Platform.OS === 'android' ? {paddingBottom: keyboardHeight} : null,
129
+ ];
130
+
131
+ const normalizedChildren = React.Children.toArray(children).map(child => {
132
+ if (typeof child === 'string' || typeof child === 'number') {
133
+ const text = String(child).trim();
134
+ if (!text || text === '.') return null;
135
+ return <Text>{text}</Text>;
136
+ }
137
+ return child;
138
+ });
139
+
140
+ return (
141
+ <Modal
142
+ visible={showing}
143
+ animationType="none"
144
+ transparent
145
+ statusBarTranslucent
146
+ onRequestClose={onRequestClose}>
147
+ <GestureHandlerRootView style={styles.gestureRoot}>
148
+ <KeyboardAvoidingView
149
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
150
+ style={overlayStyle}>
151
+ <Animated.View
152
+ style={[
153
+ StyleSheet.absoluteFillObject,
154
+ styles.overlayBg,
155
+ {opacity: overlayOpacity},
156
+ ]}
157
+ />
158
+ <Animated.View
159
+ style={[styles.content, {transform: [{translateY: slideY}]}]}>
160
+ {normalizedChildren}
161
+ </Animated.View>
162
+ <Toasts
163
+ providerKey={TOAST_PROVIDER_KEYS.MODAL}
164
+ extraInsets={TOAST_EXTRA_INSETS}
165
+ onToastPress={currentToast => toast.dismiss(currentToast.id)}
166
+ />
167
+ </KeyboardAvoidingView>
168
+ </GestureHandlerRootView>
169
+ </Modal>
170
+ );
171
+ }
@@ -0,0 +1,21 @@
1
+ import {StyleSheet} from 'react-native';
2
+
3
+ const styles = StyleSheet.create({
4
+ gestureRoot: {
5
+ flex: 1,
6
+ },
7
+ overlay: {
8
+ flex: 1,
9
+ justifyContent: 'flex-end',
10
+ },
11
+ overlayBg: {
12
+ backgroundColor: 'rgba(15, 23, 42, 0.4)',
13
+ },
14
+ content: {
15
+ width: '100%',
16
+ flex: 1,
17
+ justifyContent: 'flex-end',
18
+ },
19
+ });
20
+
21
+ export default styles;
@@ -0,0 +1,164 @@
1
+ import React, {useMemo, useState} from 'react';
2
+ import {
3
+ Modal,
4
+ Platform,
5
+ ScrollView,
6
+ Text,
7
+ TextInput,
8
+ TouchableOpacity,
9
+ View,
10
+ } from 'react-native';
11
+ import Icon from 'react-native-vector-icons/Feather';
12
+ import {
13
+ app_type,
14
+ app_type_base,
15
+ app_type_options,
16
+ clear_app_type,
17
+ normalize_app_type,
18
+ set_app_type,
19
+ } from '@appType';
20
+ import styles from './AppTypeSwitcher.styles';
21
+
22
+ const reloadApp = () => {
23
+ if (typeof window !== 'undefined' && typeof window.location?.reload === 'function') {
24
+ window.location.reload();
25
+ }
26
+ };
27
+
28
+ function AppTypeOptionsModal({visible, currentAppType, onClose, onSelect}) {
29
+ const [query, setQuery] = useState('');
30
+
31
+ const filteredOptions = useMemo(() => {
32
+ const normalizedQuery = query.trim().toLowerCase();
33
+ if (!normalizedQuery) {
34
+ return app_type_options;
35
+ }
36
+
37
+ return app_type_options.filter(option =>
38
+ option.toLowerCase().includes(normalizedQuery),
39
+ );
40
+ }, [query]);
41
+
42
+ if (!visible) {
43
+ return null;
44
+ }
45
+
46
+ return (
47
+ <Modal visible transparent animationType="fade" onRequestClose={onClose}>
48
+ <View style={styles.modalOverlay}>
49
+ <View style={styles.modalPanel}>
50
+ <View style={styles.modalHeader}>
51
+ <Text style={styles.modalTitle}>Selecionar tipo de app</Text>
52
+ <TouchableOpacity
53
+ accessibilityRole="button"
54
+ accessibilityLabel="Fechar seletor"
55
+ style={styles.closeButton}
56
+ onPress={onClose}
57
+ >
58
+ <Icon name="x" size={18} color="#334155" />
59
+ </TouchableOpacity>
60
+ </View>
61
+ <TextInput
62
+ style={styles.modalSearch}
63
+ value={query}
64
+ onChangeText={setQuery}
65
+ placeholder="Filtrar"
66
+ placeholderTextColor="#94A3B8"
67
+ />
68
+ <ScrollView contentContainerStyle={styles.optionList}>
69
+ {filteredOptions.map(option => {
70
+ const selected = option === currentAppType;
71
+
72
+ return (
73
+ <TouchableOpacity
74
+ key={option}
75
+ accessibilityRole="button"
76
+ accessibilityLabel={option}
77
+ style={[styles.optionRow, selected && styles.optionRowActive]}
78
+ onPress={() => onSelect(option)}
79
+ >
80
+ <Text style={[styles.optionText, selected && styles.optionTextActive]}>
81
+ {option}
82
+ </Text>
83
+ {selected && <Text style={styles.optionHint}>Visão atual</Text>}
84
+ </TouchableOpacity>
85
+ );
86
+ })}
87
+ </ScrollView>
88
+ </View>
89
+ </View>
90
+ </Modal>
91
+ );
92
+ }
93
+
94
+ const AppTypeSwitcher = () => {
95
+ const buildAppType = normalize_app_type(app_type_base);
96
+ const currentAppType = normalize_app_type(app_type);
97
+ const [selectorOpen, setSelectorOpen] = useState(false);
98
+
99
+ if (Platform.OS !== 'web' || buildAppType !== 'ADMIN') {
100
+ return null;
101
+ }
102
+
103
+ const handleSelect = appType => {
104
+ const normalizedAppType = normalize_app_type(appType);
105
+ if (!normalizedAppType || normalizedAppType === currentAppType) {
106
+ setSelectorOpen(false);
107
+ return;
108
+ }
109
+
110
+ if (normalizedAppType === buildAppType) {
111
+ clear_app_type();
112
+ } else {
113
+ set_app_type(normalizedAppType);
114
+ }
115
+
116
+ setSelectorOpen(false);
117
+ reloadApp();
118
+ };
119
+
120
+ const handleReset = () => {
121
+ clear_app_type();
122
+ setSelectorOpen(false);
123
+ reloadApp();
124
+ };
125
+
126
+ return (
127
+ <>
128
+ <View style={styles.container}>
129
+ <Text style={styles.label}>Tipo de app</Text>
130
+ <TouchableOpacity
131
+ accessibilityRole="button"
132
+ accessibilityLabel="Selecionar tipo de app"
133
+ activeOpacity={0.82}
134
+ style={styles.button}
135
+ onPress={() => setSelectorOpen(true)}
136
+ >
137
+ <Text style={styles.buttonText}>{currentAppType}</Text>
138
+ <Icon name="chevron-down" size={16} color="#334155" />
139
+ </TouchableOpacity>
140
+
141
+ {currentAppType !== buildAppType && (
142
+ <TouchableOpacity
143
+ accessibilityRole="button"
144
+ accessibilityLabel="Voltar para ADMIN"
145
+ activeOpacity={0.82}
146
+ style={styles.resetButton}
147
+ onPress={handleReset}
148
+ >
149
+ <Text style={styles.resetText}>Voltar para ADMIN</Text>
150
+ </TouchableOpacity>
151
+ )}
152
+ </View>
153
+
154
+ <AppTypeOptionsModal
155
+ visible={selectorOpen}
156
+ currentAppType={currentAppType}
157
+ onClose={() => setSelectorOpen(false)}
158
+ onSelect={handleSelect}
159
+ />
160
+ </>
161
+ );
162
+ };
163
+
164
+ export default AppTypeSwitcher;
@@ -0,0 +1,109 @@
1
+ import {StyleSheet} from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ container: {
5
+ alignItems: 'flex-end',
6
+ gap: 6,
7
+ },
8
+ label: {
9
+ color: '#64748B',
10
+ fontSize: 11,
11
+ fontWeight: '800',
12
+ letterSpacing: 0.2,
13
+ },
14
+ button: {
15
+ alignItems: 'center',
16
+ backgroundColor: '#FFFFFF',
17
+ borderColor: '#D8E0EA',
18
+ borderRadius: 999,
19
+ borderWidth: 1,
20
+ flexDirection: 'row',
21
+ gap: 8,
22
+ justifyContent: 'space-between',
23
+ minWidth: 164,
24
+ paddingHorizontal: 12,
25
+ paddingVertical: 8,
26
+ },
27
+ buttonText: {
28
+ color: '#0F172A',
29
+ fontSize: 13,
30
+ fontWeight: '800',
31
+ },
32
+ resetButton: {
33
+ paddingHorizontal: 2,
34
+ paddingVertical: 2,
35
+ },
36
+ resetText: {
37
+ color: '#1D4ED8',
38
+ fontSize: 11,
39
+ fontWeight: '800',
40
+ },
41
+ modalOverlay: {
42
+ flex: 1,
43
+ backgroundColor: 'rgba(15, 23, 42, 0.46)',
44
+ justifyContent: 'center',
45
+ padding: 16,
46
+ },
47
+ modalPanel: {
48
+ backgroundColor: '#FFFFFF',
49
+ borderRadius: 18,
50
+ maxHeight: '80%',
51
+ overflow: 'hidden',
52
+ },
53
+ modalHeader: {
54
+ alignItems: 'center',
55
+ borderBottomColor: '#E2E8F0',
56
+ borderBottomWidth: 1,
57
+ flexDirection: 'row',
58
+ justifyContent: 'space-between',
59
+ paddingHorizontal: 16,
60
+ paddingVertical: 14,
61
+ },
62
+ modalTitle: {
63
+ color: '#0F172A',
64
+ fontSize: 16,
65
+ fontWeight: '800',
66
+ },
67
+ closeButton: {
68
+ alignItems: 'center',
69
+ borderRadius: 16,
70
+ height: 32,
71
+ justifyContent: 'center',
72
+ width: 32,
73
+ },
74
+ modalSearch: {
75
+ backgroundColor: '#F8FAFC',
76
+ borderBottomColor: '#E2E8F0',
77
+ borderBottomWidth: 1,
78
+ color: '#0F172A',
79
+ fontSize: 13,
80
+ fontWeight: '700',
81
+ minHeight: 42,
82
+ paddingHorizontal: 16,
83
+ paddingVertical: 10,
84
+ },
85
+ optionList: {
86
+ paddingVertical: 8,
87
+ },
88
+ optionRow: {
89
+ paddingHorizontal: 16,
90
+ paddingVertical: 12,
91
+ },
92
+ optionRowActive: {
93
+ backgroundColor: '#EFF6FF',
94
+ },
95
+ optionText: {
96
+ color: '#334155',
97
+ fontSize: 14,
98
+ fontWeight: '800',
99
+ },
100
+ optionTextActive: {
101
+ color: '#1D4ED8',
102
+ },
103
+ optionHint: {
104
+ color: '#64748B',
105
+ fontSize: 11,
106
+ fontWeight: '600',
107
+ marginTop: 2,
108
+ },
109
+ });
@@ -1,6 +1,7 @@
1
1
  import React, {useEffect, useMemo, useRef} from 'react';
2
2
  import {NativeModules} from 'react-native';
3
- import {env as APP_ENV} from '@env';
3
+ import {app_type} from '@appType';
4
+ import { env as APP_ENV } from '@env';
4
5
  import {useStore} from '@store';
5
6
  import DeviceInfo from 'react-native-device-info';
6
7
  import {resolveAppDomain} from '@controleonline/ui-common/src/utils/appDomain';
@@ -61,7 +62,7 @@ const BackgroundRuntimeBridge = () => {
61
62
 
62
63
  const bundleId = safeTrim(DeviceInfo.getBundleId());
63
64
  const runtimeAppKey =
64
- bundleId || safeTrim(APP_ENV.APP_TYPE).toUpperCase() || 'app';
65
+ bundleId || safeTrim(app_type).toUpperCase() || 'app';
65
66
  const runtimeDeviceId = normalizeDeviceId(runtimeDevice?.id);
66
67
  const runtimeDeviceType = normalizeDeviceType(
67
68
  runtimeDeviceConfig?.type ||
@@ -70,7 +71,7 @@ const BackgroundRuntimeBridge = () => {
70
71
  );
71
72
  const currentCompanyId = safeTrim(currentCompany?.id);
72
73
  const sessionToken = readSessionToken();
73
- const isManagerRuntime = isManagerAppType(APP_ENV?.APP_TYPE);
74
+ const isManagerRuntime = isManagerAppType(app_type);
74
75
  const managerOrderNotificationPreferences =
75
76
  resolveManagerOrderNotificationPreferences(user);
76
77
  const userAlertSoundUrl = safeTrim(
@@ -162,7 +163,7 @@ const BackgroundRuntimeBridge = () => {
162
163
  companyAlias: safeTrim(currentCompany?.alias || currentCompany?.name),
163
164
  companyId: currentCompanyId,
164
165
  appDomain: safeTrim(resolveAppDomain(APP_ENV.DOMAIN)),
165
- appType: safeTrim(APP_ENV.APP_TYPE).toUpperCase(),
166
+ appType: safeTrim(app_type).toUpperCase(),
166
167
  backgroundEnabled: true,
167
168
  deviceId: runtimeDeviceId,
168
169
  deviceType: runtimeDeviceType,